[Beignet] [PATCH] Add Gen's specific program struct.
junyan.he at inbox.com
junyan.he at inbox.com
Thu Mar 2 10:15:37 UTC 2017
From: Junyan He <junyan.he at intel.com>
cl_program_gen struct is for Gen device. Every time
a program is created, cl_program_gen will be generated
by using libelf. The according ELF format binary will
be parsed and stored in cl_program_gen.
Signed-off-by: Junyan He <junyan.he at intel.com>
---
src/cl_program.c | 1 -
src/cl_program.h | 17 +++
src/gen/cl_gen.h | 71 +++++++++++
src/gen/cl_program_gen.c | 320 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 408 insertions(+), 1 deletion(-)
create mode 100644 src/gen/cl_gen.h
create mode 100644 src/gen/cl_program_gen.c
diff --git a/src/cl_program.c b/src/cl_program.c
index 363aed5..46f9d1f 100644
--- a/src/cl_program.c
+++ b/src/cl_program.c
@@ -117,7 +117,6 @@ cl_program_delete(cl_program p)
cl_free(p);
}
-#define BUILD_LOG_MAX_SIZE (1024*1024U)
LOCAL cl_program
cl_program_new(cl_context ctx)
{
diff --git a/src/cl_program.h b/src/cl_program.h
index 6e8e84a..4afa553 100644
--- a/src/cl_program.h
+++ b/src/cl_program.h
@@ -28,6 +28,23 @@
#include <stdint.h>
#include <stdlib.h>
+#define BUILD_LOG_MAX_SIZE (256 * 1024U)
+
+typedef struct _cl_program_for_device {
+ cl_device_id device; /* Point to the device it belong to */
+ char *binary; /* Program binary. */
+ size_t binary_sz; /* The binary size. */
+ cl_uint binary_type; /* binary type: COMPILED_OBJECT(LLVM IR),
+ LIBRARY(LLVM IR with option "-create-library"),
+ or EXECUTABLE(GEN binary). */
+ size_t build_log_max_sz; /* build log maximum size in byte.*/
+ char build_log[BUILD_LOG_MAX_SIZE]; /* The build log for this program. */
+ size_t build_log_sz; /* The actual build log size.*/
+ cl_uint kernel_num; /* Kernel number */
+ char **kernel_names; /* All kernel names of this program */
+} _cl_program_for_device;
+typedef _cl_program_for_device *cl_program_for_device;
+
// This is the structure ouput by the compiler
struct _gbe_program;
diff --git a/src/gen/cl_gen.h b/src/gen/cl_gen.h
new file mode 100644
index 0000000..2926bc7
--- /dev/null
+++ b/src/gen/cl_gen.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __CL_GEN_H__
+#define __CL_GEN_H__
+
+#include "intel_driver.h"
+#include "cl_program.h"
+#include "cl_kernel.h"
+#include "cl_utils.h"
+#include "cl_alloc.h"
+#include "cl_platform_id.h"
+#include "cl_mem.h"
+#include "cl_image.h"
+#include "cl_device_id.h"
+#include "cl_sampler.h"
+#include "cl_command_queue.h"
+#include "cl_event.h"
+
+#include <libelf.h>
+#include <gelf.h>
+#include <string.h>
+
+/*********************************** Program *****************************************/
+typedef struct _cl_program_gen {
+ _cl_program_for_device prog_base;
+ Elf *elf;
+ size_t sec_num;
+ Elf_Scn *strtab;
+ cl_int strtab_sec_index;
+ Elf_Data *strtab_data;
+ Elf_Scn *text;
+ cl_int text_sec_index;
+ Elf_Data *text_data;
+ Elf_Scn *rodata;
+ cl_int rodata_sec_index;
+ Elf_Data *rodata_data;
+ Elf_Scn *symtab;
+ cl_int symtab_sec_index;
+ Elf_Data *symtab_data;
+ size_t symtab_entry_num;
+ Elf_Scn *func_gpu_info;
+ cl_int func_gpu_info_sec_index;
+ Elf_Data *func_gpu_info_data;
+ Elf_Scn *func_cl_info;
+ cl_int func_cl_info_sec_index;
+ Elf_Data *func_cl_info_data;
+} _cl_program_gen;
+typedef _cl_program_gen *cl_program_gen;
+
+extern void *cl_program_new_gen(cl_device_id device, cl_program p);
+extern void cl_program_delete_gen(cl_device_id device, cl_program p);
+extern cl_int cl_program_load_binary_gen(cl_device_id device, cl_program prog);
+extern cl_int cl_program_get_info_gen(cl_device_id device, cl_program program,
+ cl_uint param_name, void *param_value);
+
+#endif /* End of __CL_GEN_H__ */
diff --git a/src/gen/cl_program_gen.c b/src/gen/cl_program_gen.c
new file mode 100644
index 0000000..58be603
--- /dev/null
+++ b/src/gen/cl_program_gen.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "cl_gen.h"
+
+struct binary_type_header_info {
+ unsigned char header[4];
+ cl_uint size;
+ cl_uint type;
+};
+
+static struct binary_type_header_info binary_type_header[4] = {
+ {{'B', 'C', 0xC0, 0xDE}, 4, CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT},
+ {{0x7f, 'E', 'L', 'F'}, 4, CL_PROGRAM_BINARY_TYPE_EXECUTABLE}};
+
+static cl_int
+cl_program_get_binary_type_gen(const char *buf)
+{
+ int i;
+ for (i = 0; i < sizeof(binary_type_header) / sizeof(struct binary_type_header_info); i++) {
+ if (memcmp((char *)buf, binary_type_header[i].header, binary_type_header[i].size) == 0) {
+ return binary_type_header[i].type;
+ }
+ }
+
+ return CL_PROGRAM_BINARY_TYPE_NONE;
+}
+
+static Elf *
+cl_program_parse_gen_elf_stream(cl_char *bit_stream, size_t size)
+{
+ Elf_Kind ek;
+ Elf *elf_program = NULL;
+
+ elf_program = elf_memory((char *)bit_stream, size);
+ if (elf_program == NULL) {
+ return NULL;
+ }
+
+ ek = elf_kind(elf_program);
+ if (ek != ELF_K_ELF) {
+ elf_end(elf_program);
+ return NULL;
+ }
+
+ return elf_program;
+}
+
+LOCAL void *
+cl_program_new_gen(cl_device_id device, cl_program p)
+{
+ cl_program_gen gen_elf = cl_calloc(1, sizeof(_cl_program_gen));
+ if (gen_elf == NULL)
+ return NULL;
+
+ gen_elf->prog_base.device = device;
+ gen_elf->prog_base.build_log_max_sz = BUILD_LOG_MAX_SIZE;
+ gen_elf->prog_base.binary_type = CL_PROGRAM_BINARY_TYPE_NONE;
+ return (void *)gen_elf;
+}
+
+LOCAL void
+cl_program_delete_gen(cl_device_id device, cl_program p)
+{
+ cl_program_gen gen_elf = NULL;
+ cl_program_for_device pd;
+ DEV_PRIVATE_DATA(p, device, gen_elf);
+ pd = &gen_elf->prog_base;
+ int i;
+
+ if (pd->kernel_names) {
+ assert(pd->kernel_num > 0);
+ for (i = 0; i < pd->kernel_num; i++) {
+ if (pd->kernel_names[i])
+ cl_free(pd->kernel_names[i]);
+ }
+ cl_free(pd->kernel_names);
+ }
+ pd->kernel_names = NULL;
+
+ if (gen_elf->elf)
+ elf_end(gen_elf->elf);
+ gen_elf->elf = NULL;
+
+ cl_free(gen_elf);
+}
+
+static cl_int
+cl_program_load_binary_gen_elf(cl_device_id device, cl_program prog)
+{
+ cl_program_for_device pd;
+ cl_program_gen elf = NULL;
+ Elf *elf_p = NULL;
+ GElf_Shdr sec_header;
+ GElf_Shdr *p_sec_header = NULL;
+ Elf_Scn *elf_sec = NULL;
+ Elf_Scn *sh_strtab;
+ Elf_Data *sh_strtab_data;
+ GElf_Sym *p_sym_entry;
+ GElf_Sym sym_entry;
+ char *name;
+ int ret;
+ size_t val = 0;
+ int i, j;
+
+ DEV_PRIVATE_DATA(prog, device, elf);
+ pd = &elf->prog_base;
+
+ assert(pd->binary != NULL);
+ assert(pd->binary_sz > 4);
+ assert(pd->binary_type == CL_PROGRAM_BINARY_TYPE_EXECUTABLE);
+
+ elf_p = cl_program_parse_gen_elf_stream((cl_char *)pd->binary, pd->binary_sz);
+ if (elf_p == NULL) {
+ return CL_INVALID_PROGRAM;
+ }
+
+ elf->elf = elf_p;
+
+ ret = elf_getphdrnum(elf_p, &val);
+ if (ret < 0) {
+ elf_end(elf_p);
+ elf->elf = NULL;
+ return CL_INVALID_PROGRAM;
+ }
+
+ /* Should always have sections. */
+ ret = elf_getshdrnum(elf_p, &val);
+ if (ret < 0 || val <= 0) {
+ elf_end(elf_p);
+ elf->elf = NULL;
+ return CL_INVALID_PROGRAM;
+ }
+ elf->sec_num = val;
+
+ /* Should always have a .shstrtab section. */
+ ret = elf_getshdrstrndx(elf_p, &val);
+ if (ret < 0) {
+ elf_end(elf_p);
+ elf->elf = NULL;
+ return CL_INVALID_PROGRAM;
+ }
+
+ /* Get the section name string buffer. */
+ sh_strtab = elf_getscn(elf_p, val);
+ assert(sh_strtab);
+ sh_strtab_data = elf_getdata(sh_strtab, NULL);
+ if (sh_strtab_data == NULL) {
+ elf_end(elf_p);
+ elf->elf = NULL;
+ return CL_INVALID_PROGRAM;
+ }
+
+ /* Find all the special sections. */
+ for (i = 0; i < (int)(elf->sec_num); i++) {
+ elf_sec = elf_getscn(elf_p, i);
+ assert(elf_sec);
+ p_sec_header = gelf_getshdr(elf_sec, &sec_header);
+ assert(p_sec_header == &sec_header);
+ if (strcmp(sh_strtab_data->d_buf + p_sec_header->sh_name, ".text") == 0) {
+ elf->text = elf_sec;
+ elf->text_sec_index = i;
+ } else if (strcmp(sh_strtab_data->d_buf + p_sec_header->sh_name, ".symtab") == 0) {
+ elf->symtab = elf_sec;
+ elf->symtab_sec_index = i;
+ } else if (strcmp(sh_strtab_data->d_buf + p_sec_header->sh_name, ".strtab") == 0) {
+ elf->strtab = elf_sec;
+ elf->strtab_sec_index = i;
+ } else if (strcmp(sh_strtab_data->d_buf + p_sec_header->sh_name, ".note.gpu_info") == 0) {
+ elf->func_gpu_info = elf_sec;
+ elf->func_gpu_info_sec_index = i;
+ } else if (strcmp(sh_strtab_data->d_buf + p_sec_header->sh_name, ".note.cl_info") == 0) {
+ elf->func_cl_info = elf_sec;
+ elf->func_cl_info_sec_index = i;
+ } else if (strcmp(sh_strtab_data->d_buf + p_sec_header->sh_name, ".rodata") == 0) {
+ elf->rodata = elf_sec;
+ elf->rodata_sec_index = i;
+ }
+ }
+
+ if (elf->text == NULL || elf->symtab == NULL ||
+ elf->strtab == NULL || elf->func_gpu_info == NULL) {
+ elf_end(elf_p);
+ elf->elf = NULL;
+ return CL_INVALID_PROGRAM;
+ }
+
+ elf->strtab_data = elf_getdata(elf->strtab, NULL);
+ assert(elf->strtab_data);
+ elf->text_data = elf_getdata(elf->text, NULL);
+ assert(elf->text_data);
+ elf->symtab_data = elf_getdata(elf->symtab, NULL);
+ assert(elf->symtab_data);
+ p_sec_header = gelf_getshdr(elf->symtab, &sec_header);
+ assert(p_sec_header == &sec_header);
+ elf->symtab_entry_num = p_sec_header->sh_size / p_sec_header->sh_entsize;
+ assert(p_sec_header->sh_size % p_sec_header->sh_entsize == 0);
+ elf->func_gpu_info_data = elf_getdata(elf->func_gpu_info, NULL);
+ assert(elf->func_gpu_info_data);
+ if (elf->rodata) {
+ elf->rodata_data = elf_getdata(elf->rodata, NULL);
+ assert(elf->rodata_data);
+ }
+ if (elf->func_cl_info) {
+ elf->func_cl_info_data = elf_getdata(elf->func_cl_info, NULL);
+ assert(elf->func_cl_info_data);
+ }
+
+ /* Add all kernel names */
+ assert(pd->kernel_names == NULL);
+ assert(pd->kernel_num == 0);
+ for (i = 0; i < (int)(elf->symtab_entry_num); i++) {
+ p_sym_entry = gelf_getsym(elf->symtab_data, i, &sym_entry);
+ assert(p_sym_entry == &sym_entry);
+ if ((p_sym_entry->st_info & 0x0f) != STT_FUNC)
+ continue;
+ if (((p_sym_entry->st_info & 0x0f0) >> 4) != STB_GLOBAL)
+ continue;
+
+ name = p_sym_entry->st_name + elf->strtab_data->d_buf;
+ assert(name);
+
+ pd->kernel_num++;
+ }
+ if (pd->kernel_num == 0) { // A program without kernel ?
+ elf_end(elf_p);
+ elf->elf = NULL;
+ return CL_INVALID_PROGRAM;
+ }
+
+ pd->kernel_names = cl_calloc(pd->kernel_num, sizeof(char *));
+ if (pd->kernel_names == NULL) {
+ elf_end(elf_p);
+ elf->elf = NULL;
+ return CL_OUT_OF_HOST_MEMORY;
+ }
+ j = 0;
+ for (i = 0; i < (int)(elf->symtab_entry_num); i++) {
+ p_sym_entry = gelf_getsym(elf->symtab_data, i, &sym_entry);
+ assert(p_sym_entry == &sym_entry);
+ if ((p_sym_entry->st_info & 0x0f) != STT_FUNC)
+ continue;
+ if (((p_sym_entry->st_info & 0x0f0) >> 4) != STB_GLOBAL)
+ continue;
+
+ pd->kernel_names[j] =
+ cl_calloc(1, strlen(p_sym_entry->st_name + elf->strtab_data->d_buf) + 1);
+ if (pd->kernel_names[j] == NULL) {
+ elf_end(elf_p);
+ elf->elf = NULL;
+ return CL_OUT_OF_HOST_MEMORY;
+ }
+
+ memcpy(pd->kernel_names[j], p_sym_entry->st_name + elf->strtab_data->d_buf,
+ strlen(p_sym_entry->st_name + elf->strtab_data->d_buf) + 1);
+ j++;
+ }
+
+ return CL_SUCCESS;
+}
+
+LOCAL cl_int
+cl_program_load_binary_gen(cl_device_id device, cl_program prog)
+{
+ cl_program_gen pg = NULL;
+ cl_program_for_device pd = NULL;
+
+ DEV_PRIVATE_DATA(prog, device, pg);
+ pd = &pg->prog_base;
+
+ assert(pd->binary != NULL);
+
+ //need at least bytes to check the binary type.
+ if (pd->binary_sz < 5)
+ return CL_INVALID_PROGRAM_EXECUTABLE;
+
+ if (pd->binary_type == CL_PROGRAM_BINARY_TYPE_NONE) { // Need to recognize it first
+ pd->binary_type = cl_program_get_binary_type_gen(pd->binary);
+ if (pd->binary_type == CL_PROGRAM_BINARY_TYPE_NONE)
+ return CL_INVALID_PROGRAM_EXECUTABLE;
+ }
+
+ if (pd->binary_type != CL_PROGRAM_BINARY_TYPE_EXECUTABLE)
+ return CL_SUCCESS;
+
+ return cl_program_load_binary_gen_elf(device, prog);
+}
+
+LOCAL cl_int
+cl_program_get_info_gen(cl_device_id device, cl_program program, cl_uint param_name, void *param_value)
+{
+ cl_program_gen program_gen;
+ DEV_PRIVATE_DATA(program, device, program_gen);
+
+ if (param_name == CL_PROGRAM_BUILD_GLOBAL_VARIABLE_TOTAL_SIZE) {
+ if (program_gen->prog_base.binary_type != CL_PROGRAM_BINARY_TYPE_NONE) {
+ *(size_t *)param_value = program_gen->rodata_data->d_size;
+ } else {
+ *(size_t *)param_value = 0;
+ }
+ return CL_SUCCESS;
+ }
+
+ return CL_INVALID_VALUE;
+}
--
2.7.4
More information about the Beignet
mailing list