/* deserializes a single file from the binary. */ static size_t deserialize_file(unsigned char* buffer, char* basedir, size_t offset) { unsigned char* orig_buffer = buffer; size_t len; char* relpath = NULL; BUFFER_READ_STR2(relpath, len); assert(len > 0); char* content = NULL; BUFFER_READ_STR2(content, len); assert(len > 0); char *p = basedir + offset; strcpy(p, relpath); free(relpath); char *fullpath = basedir; if (pocl_exists(fullpath)) goto RET; char* dir = strdup(basedir); char* dirpath = dirname(dir); if (!pocl_exists(dirpath)) pocl_mkdir_p(dirpath); free(dir); pocl_write_file(fullpath, content, len, 0, 0); RET: free(content); return (buffer - orig_buffer); }
void pocl_cache_init_topdir() { if (cache_topdir_initialized) return; const char *tmp_path = pocl_get_string_option("POCL_CACHE_DIR", NULL); int needed; if (tmp_path && (pocl_exists(tmp_path))) { needed = snprintf(cache_topdir, POCL_FILENAME_LENGTH, "%s", tmp_path); } else { #ifdef POCL_ANDROID char* process_name = pocl_get_process_name(); needed = snprintf(cache_topdir, POCL_FILENAME_LENGTH, "/data/data/%s/cache/", process_name); free(process_name); if (!pocl_exists(cache_topdir)) needed = snprintf(cache_topdir, POCL_FILENAME_LENGTH, "/sdcard/pocl/kcache"); #elif defined(_MSC_VER) || defined(__MINGW32__) tmp_path = getenv("LOCALAPPDATA"); if (!tmp_path) tmp_path = getenv("TEMP"); assert(tmp_path); needed = snprintf(cache_topdir, POCL_FILENAME_LENGTH, "%s\\pocl", tmp_path); #else // "If $XDG_CACHE_HOME is either not set or empty, a default equal to // $HOME/.cache should be used." // http://standards.freedesktop.org/basedir-spec/latest/ tmp_path = getenv("XDG_CACHE_HOME"); if (tmp_path && tmp_path[0] != '\0') { needed = snprintf(cache_topdir, POCL_FILENAME_LENGTH, "%s/pocl/kcache", tmp_path); } else if ((tmp_path = getenv("HOME")) != NULL) { needed = snprintf(cache_topdir, POCL_FILENAME_LENGTH, "%s/.cache/pocl/kcache", tmp_path); } else { needed = snprintf(cache_topdir, POCL_FILENAME_LENGTH, "/tmp/pocl/kcache"); } #endif } if (needed >= POCL_FILENAME_LENGTH) { POCL_ABORT("pocl: cache path longer than maximum filename length"); } assert(strlen(cache_topdir) > 0); if (pocl_mkdir_p(cache_topdir)) POCL_ABORT("Could not create topdir for cache"); cache_topdir_initialized = 1; }
int pocl_cache_device_cachedir_exists(cl_program program, unsigned device_i) { char device_cachedir_path[POCL_FILENAME_LENGTH]; program_device_dir(device_cachedir_path, program, device_i, ""); return pocl_exists(device_cachedir_path); }
char* pocl_cache_read_buildlog(cl_program program, unsigned device_i) { char buildlog_path[POCL_FILENAME_LENGTH]; if (program->build_hash[device_i][0] == 0) return NULL; program_device_dir(buildlog_path, program, device_i, POCL_BUILDLOG_FILENAME); if (!pocl_exists(buildlog_path)) return strdup(""); char* res=NULL; uint64_t filesize; if (pocl_read_file(buildlog_path, &res, &filesize)) return NULL; return res; }
int pocl_write_file(const char *path, const char* content, uint64_t count, int append, int dont_rewrite) { assert(path); assert(content); if (pocl_exists(path)) { if (dont_rewrite) { if (!append) return 0; } else { int res = pocl_remove(path); if (res) return res; } } FILE *f; if (append) f = fopen(path, "a"); else f = fopen(path, "w"); if (f == NULL) return -1; if (fwrite(content, 1, (size_t)count, f) < (size_t)count) return -1; return fclose(f); }
int pocl_write_file(const char *path, const char* content, uint64_t count, int append, int dont_rewrite) { assert(path); assert(content); if (pocl_exists(path)) { if (dont_rewrite) { if (!append) return 0; } else { int res = pocl_remove(path); if (res) { POCL_MSG_ERR ("pocl_remove(%s) failed\n", path); return res; } } } FILE *f; if (append) f = fopen(path, "a"); else f = fopen(path, "w"); if (f == NULL) { POCL_MSG_ERR ("fopen(%s) failed\n", path); return -1; } if (fwrite (content, 1, (size_t)count, f) < (size_t)count) { POCL_MSG_ERR ("fwrite(%s) failed\n", path); return -1; } if (fflush (f)) { POCL_MSG_ERR ("fflush() failed\n"); return errno; } #ifdef HAVE_FDATASYNC if (fdatasync (fileno (f))) { POCL_MSG_ERR ("fdatasync() failed\n"); return errno; } #elif defined(HAVE_FSYNC) if (fsync (fileno (f))) { POCL_MSG_ERR ("fsync() failed\n"); return errno; } #endif return fclose(f); }
/* creates either a program with binaries, or an empty program. The latter * is useful for clLinkProgram() which needs an empty program to put the * compiled results in. */ cl_program create_program_skeleton (cl_context context, cl_uint num_devices, const cl_device_id *device_list, const size_t *lengths, const unsigned char **binaries, cl_int *binary_status, cl_int *errcode_ret, int allow_empty_binaries) { cl_program program; unsigned i,j; int errcode, is_spirv_opencl; cl_device_id *unique_devlist = NULL; POCL_GOTO_ERROR_COND((context == NULL), CL_INVALID_CONTEXT); POCL_GOTO_ERROR_COND((device_list == NULL), CL_INVALID_VALUE); POCL_GOTO_ERROR_COND((num_devices == 0), CL_INVALID_VALUE); if (!allow_empty_binaries) { POCL_GOTO_ERROR_COND ((lengths == NULL), CL_INVALID_VALUE); for (i = 0; i < num_devices; ++i) { POCL_GOTO_ERROR_ON ((lengths[i] == 0 || binaries[i] == NULL), CL_INVALID_VALUE, "%i-th binary is NULL or its length==0\n", i); } } // check for duplicates in device_list[]. for (i = 0; i < context->num_devices; i++) { int count = 0; for (j = 0; j < num_devices; j++) { count += context->devices[i] == device_list[j]; } // duplicate devices POCL_GOTO_ERROR_ON((count > 1), CL_INVALID_DEVICE, "device %s specified multiple times\n", context->devices[i]->long_name); } // convert subdevices to devices and remove duplicates cl_uint real_num_devices = 0; unique_devlist = pocl_unique_device_list(device_list, num_devices, &real_num_devices); num_devices = real_num_devices; device_list = unique_devlist; // check for invalid devices in device_list[]. for (i = 0; i < num_devices; i++) { int found = 0; for (j = 0; j < context->num_devices; j++) { found |= context->devices[j] == device_list[i]; } POCL_GOTO_ERROR_ON((!found), CL_INVALID_DEVICE, "device not found in the device list of the context\n"); } if ((program = (cl_program) calloc (1, sizeof (struct _cl_program))) == NULL) { errcode = CL_OUT_OF_HOST_MEMORY; goto ERROR; } POCL_INIT_OBJECT(program); if ((program->binary_sizes = (size_t*) calloc (num_devices, sizeof(size_t))) == NULL || (program->binaries = (unsigned char**) calloc (num_devices, sizeof(unsigned char*))) == NULL || (program->pocl_binaries = (unsigned char**) calloc (num_devices, sizeof(unsigned char*))) == NULL || (program->pocl_binary_sizes = (size_t*) calloc (num_devices, sizeof(size_t))) == NULL || (program->build_log = (char**) calloc (num_devices, sizeof(char*))) == NULL || ((program->llvm_irs = (void**) calloc (num_devices, sizeof(void*))) == NULL) || ((program->build_hash = (SHA1_digest_t*) calloc (num_devices, sizeof(SHA1_digest_t))) == NULL)) { errcode = CL_OUT_OF_HOST_MEMORY; goto ERROR_CLEAN_PROGRAM_AND_BINARIES; } program->context = context; program->num_devices = num_devices; program->devices = unique_devlist; program->build_status = CL_BUILD_NONE; program->binary_type = CL_PROGRAM_BINARY_TYPE_NONE; char program_bc_path[POCL_FILENAME_LENGTH]; if (allow_empty_binaries && (lengths == NULL) && (binaries == NULL)) goto SUCCESS; for (i = 0; i < num_devices; ++i) { /* LLVM IR */ if (!strncmp((const char *)binaries[i], "BC", 2)) { program->binary_sizes[i] = lengths[i]; program->binaries[i] = (unsigned char*) malloc(lengths[i]); memcpy (program->binaries[i], binaries[i], lengths[i]); if (binary_status != NULL) binary_status[i] = CL_SUCCESS; } /* SPIR-V binary needs to be converted, and requires * linking of the converted BC */ #ifdef OCS_AVAILABLE else if (bitcode_is_spirv ((const char *)binaries[i], lengths[i], &is_spirv_opencl)) { if (is_spirv_opencl == 0) { // SPIR-V but not OpenCL-type. POCL_GOTO_ERROR_ON ( 1, CL_BUILD_PROGRAM_FAILURE, "SPIR-V binary provided, but is not using Kernel mode." "Pocl can't process this binary.\n"); } int no_spir = strstr (device_list[i]->extensions, "cl_khr_spir") == NULL; POCL_GOTO_ERROR_ON ( no_spir, CL_BUILD_PROGRAM_FAILURE, "SPIR binary provided, but device has no SPIR support"); #ifdef ENABLE_SPIRV POCL_MSG_PRINT_LLVM ( "SPIR-V binary detected, converting to LLVM SPIR\n"); char program_bc_spirv[POCL_FILENAME_LENGTH]; char program_bc_temp[POCL_FILENAME_LENGTH]; pocl_cache_write_spirv (program_bc_spirv, (const char *)binaries[i], (uint64_t)lengths[i]); pocl_cache_tempname (program_bc_temp, ".bc", NULL); char *args[] = { LLVM_SPIRV, "-r", "-o", program_bc_temp, program_bc_spirv, NULL }; errcode = pocl_run_command (args); assert (errcode == 0); /* load LLVM SPIR binary. */ uint64_t fsize; char *content; pocl_read_file (program_bc_temp, &content, &fsize); program->binary_sizes[i] = fsize; program->binaries[i] = (unsigned char *)content; pocl_remove (program_bc_temp); #else POCL_GOTO_ERROR_ON ( 1, CL_BUILD_PROGRAM_FAILURE, "SPIR binary provided, but this pocl has no SPIR-V support." "SPIR-V support requires llvm-spirv converter binary.\n"); #endif } #endif /* Poclcc binary */ else if (pocl_binary_check_binary(device_list[i], binaries[i])) { program->pocl_binary_sizes[i] = lengths[i]; program->pocl_binaries[i] = (unsigned char*) malloc (lengths[i]); memcpy (program->pocl_binaries[i], binaries[i], lengths[i]); pocl_binary_set_program_buildhash (program, i, binaries[i]); int error = pocl_cache_create_program_cachedir (program, i, NULL, 0, program_bc_path); POCL_GOTO_ERROR_ON((error != 0), CL_BUILD_PROGRAM_FAILURE, "Could not create program cachedir"); POCL_GOTO_ERROR_ON(pocl_binary_deserialize (program, i), CL_INVALID_BINARY, "Could not unpack a pocl binary\n"); /* read program.bc, can be useful later */ if (pocl_exists (program_bc_path)) { pocl_read_file (program_bc_path, (char **)(&program->binaries[i]), (uint64_t *)(&program->binary_sizes[i])); } if (binary_status != NULL) binary_status[i] = CL_SUCCESS; } /* Unknown binary */ else { POCL_MSG_WARN ("Could not recognize binary\n"); if (binary_status != NULL) binary_status[i] = CL_INVALID_BINARY; errcode = CL_INVALID_BINARY; goto ERROR_CLEAN_PROGRAM_AND_BINARIES; } } SUCCESS: POCL_RETAIN_OBJECT(context); if (errcode_ret != NULL) *errcode_ret = CL_SUCCESS; return program; ERROR_CLEAN_PROGRAM_AND_BINARIES: if (program->binaries) for (i = 0; i < num_devices; ++i) POCL_MEM_FREE(program->binaries[i]); POCL_MEM_FREE(program->binaries); POCL_MEM_FREE(program->binary_sizes); if (program->pocl_binaries) for (i = 0; i < num_devices; ++i) POCL_MEM_FREE(program->pocl_binaries[i]); POCL_MEM_FREE(program->pocl_binaries); POCL_MEM_FREE(program->pocl_binary_sizes); /*ERROR_CLEAN_PROGRAM:*/ POCL_MEM_FREE(program); ERROR: POCL_MEM_FREE(unique_devlist); if(errcode_ret != NULL) { *errcode_ret = errcode; } return NULL; }