[Beignet] [PATCH 55/57] Add binary generator for runtime.
junyan.he at inbox.com
junyan.he at inbox.com
Sun Jun 11 05:50:41 UTC 2017
From: Junyan He <junyan.he at intel.com>
We need some builtin kernel to handle some task. We need to binary
format to save the program building time.
Signed-off-by: Junyan He <junyan.he at intel.com>
---
runtime/gen/kernels/gen_bin_generater.c | 301 ++++++++++++++++++++++++++++++++
1 file changed, 301 insertions(+)
create mode 100644 runtime/gen/kernels/gen_bin_generater.c
diff --git a/runtime/gen/kernels/gen_bin_generater.c b/runtime/gen/kernels/gen_bin_generater.c
new file mode 100644
index 0000000..ea8b5c6
--- /dev/null
+++ b/runtime/gen/kernels/gen_bin_generater.c
@@ -0,0 +1,301 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <string.h>
+#include <assert.h>
+
+typedef int (*compile_program_func)(int device_id, const char *source, size_t src_length, const char **headers,
+ size_t *header_lengths, const char **header_names, int header_num,
+ const char *options, size_t err_buf_size, char *err, size_t *err_ret_size,
+ char **binary, size_t *binary_size);
+typedef int (*build_program_func)(int device_id, const char *source, size_t src_length,
+ const char *options, size_t err_buf_size, char *err,
+ size_t *err_ret_size, char **binary, size_t *binary_size);
+static compile_program_func compile_program = NULL;
+static build_program_func build_program = NULL;
+
+static char *output_file_name = NULL;
+static char *input_file_name = NULL;
+static int pci_id = 0;
+static char build_log[1024];
+
+int load_compiler(void)
+{
+ const char *gbePath = NULL;
+ void *dlhCompiler = NULL;
+ void *genCompileProgram = NULL;
+ void *genBuildProgram = NULL;
+
+ gbePath = COMPILER_BACKEND_OBJECT;
+
+ dlhCompiler = dlopen(gbePath, RTLD_LAZY | RTLD_LOCAL);
+ if (dlhCompiler == NULL)
+ return -1;
+
+ genCompileProgram = dlsym(dlhCompiler, "GenCompileProgram");
+ if (genCompileProgram == NULL) {
+ dlclose(dlhCompiler);
+ return -1;
+ }
+
+ genBuildProgram = dlsym(dlhCompiler, "GenBuildProgram");
+ if (genBuildProgram == NULL) {
+ dlclose(dlhCompiler);
+ return -1;
+ }
+
+ compile_program = genCompileProgram;
+ build_program = genBuildProgram;
+ return 0;
+}
+
+const char *file_map_open(size_t *file_len)
+{
+ void *address;
+
+ /* Open the file */
+ int fd = open(input_file_name, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ *file_len = lseek(fd, 0, SEEK_END);
+ lseek(fd, 0, SEEK_SET);
+
+ /* Map it */
+ address = mmap(0, *file_len, PROT_READ, MAP_SHARED, fd, 0);
+ if (address == NULL) {
+ return NULL;
+ }
+
+ return address;
+}
+
+static void write_out_kernel_binary(char *obj_bin, size_t obj_size, char *elf_bin, size_t elf_size)
+{
+ Elf_Kind ek;
+ Elf *elf_p = NULL;
+ int ret;
+ size_t val = 0;
+ size_t sec_num;
+ Elf_Scn *sh_strtab = NULL;
+ Elf_Data *sh_strtab_data = NULL;
+ Elf_Scn *elf_sec = NULL;
+ GElf_Shdr sec_header;
+ GElf_Shdr *p_sec_header = NULL;
+ int i, j;
+ Elf_Scn *symtab = NULL;
+ Elf_Data *symtab_data = NULL;
+ size_t symtab_entry_num;
+ Elf_Scn *strtab = NULL;
+ Elf_Data *strtab_data = NULL;
+ GElf_Sym *p_sym_entry = NULL;
+ GElf_Sym sym_entry;
+ char *name;
+ FILE *fp;
+ char *p = NULL;
+ char *q = NULL;
+
+ elf_p = elf_memory(elf_bin, elf_size);
+ if (elf_p == NULL) {
+ printf("Can not parse elf file\n");
+ exit(-1);
+ }
+
+ ek = elf_kind(elf_p);
+ if (ek != ELF_K_ELF) {
+ elf_end(elf_p);
+ printf("Can not parse elf file, not a valid elf file\n");
+ exit(-1);
+ }
+
+ ret = elf_getphdrnum(elf_p, &val);
+ if (ret < 0) {
+ elf_end(elf_p);
+ printf("Can not parse elf file, not a valid elf file\n");
+ exit(-1);
+ }
+
+ /* Should always have sections. */
+ ret = elf_getshdrnum(elf_p, &val);
+ if (ret < 0 || val <= 0) {
+ printf("Can not parse elf file, not a valid elf file\n");
+ exit(-1);
+ }
+ sec_num = val;
+
+ /* Should always have a .shstrtab section. */
+ ret = elf_getshdrstrndx(elf_p, &val);
+ if (ret < 0) {
+ elf_end(elf_p);
+ printf("Can not parse elf file, not a valid elf file\n");
+ exit(-1);
+ }
+ /* 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);
+ printf("Can not parse elf file, not a valid elf file\n");
+ exit(-1);
+ }
+
+ /* Find all the special sections. */
+ for (i = 0; i < (int)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, ".symtab") == 0) {
+ symtab = elf_sec;
+ } else if (strcmp(sh_strtab_data->d_buf + p_sec_header->sh_name, ".strtab") == 0) {
+ strtab = elf_sec;
+ }
+ }
+
+ if (symtab == NULL || strtab == NULL) {
+ printf("Can not parse elf file, not a valid elf file\n");
+ exit(-1);
+ }
+
+ strtab_data = elf_getdata(strtab, NULL);
+ assert(strtab_data);
+ symtab_data = elf_getdata(symtab, NULL);
+ assert(symtab_data);
+ p_sec_header = gelf_getshdr(symtab, &sec_header);
+ assert(p_sec_header == &sec_header);
+ 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);
+
+ fp = fopen(output_file_name, "w");
+ if (fp == NULL) {
+ printf("Can not open file to output\n");
+ exit(-1);
+ }
+
+ fprintf(fp, "%s", "#include <stddef.h>\n");
+
+ p = strrchr(output_file_name, '/');
+ if (p == NULL) {
+ printf("Output path %s is invalid\n", output_file_name);
+ exit(-1);
+ }
+ while (*p == '/')
+ p++;
+
+ q = p;
+ while (*q != '.')
+ q++;
+ *q = 0;
+
+ fprintf(fp, "char * %s_kernels = \n\"", p);
+
+ /* Add all kernel names */
+ j = 0;
+ for (i = 0; i < (int)(symtab_entry_num); i++) {
+ if (j)
+ fprintf(fp, ";");
+
+ p_sym_entry = gelf_getsym(symtab_data, i, &sym_entry);
+ assert(p_sym_entry == &sym_entry);
+ if (ELF32_ST_TYPE(p_sym_entry->st_info) != STT_FUNC)
+ continue;
+ if (ELF32_ST_BIND(p_sym_entry->st_info) != STB_GLOBAL)
+ continue;
+
+ name = p_sym_entry->st_name + strtab_data->d_buf;
+ assert(name);
+ fprintf(fp, "%s", name);
+ j++;
+ }
+ fprintf(fp, "\";\n");
+
+ /* Output the binary */
+ fprintf(fp, "char %s[] = {\n", p);
+ for (i = 0; i < (int)obj_size; i++) {
+ unsigned char c = obj_bin[i];
+ fprintf(fp, "0x%2.2x", c);
+ if (i != (int)obj_size - 1)
+ fprintf(fp, ", ");
+ }
+ fprintf(fp, "};\n");
+
+ fprintf(fp, "size_t %s_size = %ld;\n", p, obj_size);
+}
+
+int main(int argc, const char **argv)
+{
+ int oc;
+ size_t file_sz = 0;
+ const char *file_content = NULL;
+ int ret;
+ size_t err_log_sz = 0;
+ char *obj_bin = NULL;
+ size_t obj_size = 0;
+ char *elf_bin = NULL;
+ size_t elf_size = 0;
+
+ while ((oc = getopt(argc, (char *const *)argv, "i:o:p:s")) != -1) {
+ switch (oc) {
+ case 'p':
+ pci_id = atoi(optarg);
+ break;
+
+ case 'i':
+ input_file_name = optarg;
+ break;
+
+ case 'o':
+ output_file_name = optarg;
+ break;
+
+ default:
+ printf("unknown opt!!!\n");
+ exit(-1);
+ }
+ }
+
+ if (input_file_name == NULL) {
+ printf("unknown input_file_name file name\n");
+ exit(-1);
+ }
+ if (output_file_name == NULL) {
+ printf("unknown output_file_name file name\n");
+ exit(-1);
+ }
+
+ if (load_compiler() < 0) {
+ printf("can not load compiler\n");
+ exit(-1);
+ }
+
+ file_content = file_map_open(&file_sz);
+ if (file_content == NULL) {
+ printf("can not open file %s\n", input_file_name);
+ exit(-1);
+ }
+
+ if (pci_id == 0)
+ pci_id = 0x5A84; // Set a common one.
+
+ ret = (*compile_program)(pci_id, file_content, file_sz + 1, NULL, NULL, NULL, 0, NULL,
+ sizeof(build_log), build_log, &err_log_sz, &obj_bin, &obj_size);
+ if (ret == 0) {
+ printf("Compiler program error, error msg is \n%s\n", build_log);
+ exit(-1);
+ }
+
+ ret = (*build_program)(pci_id, file_content, file_sz + 1, NULL, sizeof(build_log), build_log, &err_log_sz, &elf_bin, &elf_size);
+ if (ret == 0) {
+ printf("Build program error, error msg is \n%s\n", build_log);
+ exit(-1);
+ }
+
+ write_out_kernel_binary(obj_bin, obj_size, elf_bin, elf_size);
+}
--
2.7.4
More information about the Beignet
mailing list