103 #define CCL_C_DESCRIPTION "Static kernel compiler and analyzer"
105 #define ccl_c_get_build_status_str(build_status) \
106 (build_status) == CL_BUILD_NONE ? "Program not built (unexpected)" : \
107 ((build_status) == CL_BUILD_ERROR ? "Error" : \
108 (((build_status) == CL_BUILD_SUCCESS ? "Success" : \
109 ((((build_status) == CL_BUILD_IN_PROGRESS ? "In progress (unexpected)" : \
112 #define ccl_c_is_build_error(err) \
113 (((err != NULL) && (err->domain == CCL_OCL_ERROR) && \
114 ((err->code == CL_BUILD_PROGRAM_FAILURE) || \
115 (err->code == CL_COMPILE_PROGRAM_FAILURE) || \
116 (err->code == CL_LINK_PROGRAM_FAILURE))))
118 #define ccl_c_info_unavailable(err) \
119 ((err) != NULL) && ((err)->domain == CCL_ERROR) && \
120 ((err)->code == CCL_ERROR_INFO_UNAVAILABLE_OCL)
123 typedef enum ccl_c_tasks {
130 static gboolean opt_list = FALSE;
131 static guint dev_idx = CCL_UTILS_NODEVICE;
132 static guint task = CCL_C_BUILD;
133 static gchar* options = NULL;
134 static gchar** src_files = NULL;
135 static gchar** bin_files = NULL;
136 static gchar** src_h_files = NULL;
137 static gchar** src_h_names = NULL;
138 static gchar** kernel_names = NULL;
139 static gchar* output = NULL;
140 static gchar* bld_log_out = NULL;
141 static gboolean version = FALSE;
144 static GOptionEntry entries[] = {
145 {
"list",
'l', 0, G_OPTION_ARG_NONE, &opt_list,
146 "List available devices and exit.", NULL},
147 {
"device",
'd', 0, G_OPTION_ARG_INT, &dev_idx,
148 "Specify a device on which to perform the task.",
"DEV"},
149 {
"task",
't', 0, G_OPTION_ARG_INT, &task,
150 "0 (Build, default), 1 (Compile) or 2 (Link). Tasks 1 and 2 are only "
151 "available for platforms with support for OpenCL 1.2 or higher.",
153 {
"options",
'0', 0, G_OPTION_ARG_STRING, &options,
154 "Compiler/linker options.",
"OPTIONS"},
155 {
"src",
's', 0, G_OPTION_ARG_FILENAME_ARRAY, &src_files,
156 "Source input files. This option can be specified multiple times.",
158 {
"input-headers",
'i', 0, G_OPTION_ARG_FILENAME_ARRAY, &src_h_files,
159 "Embedded header input files for the compile task. This option can be "
160 "specified multiple times.",
"FILE"},
161 {
"header-include-names",
'n', 0, G_OPTION_ARG_STRING_ARRAY, &src_h_names,
162 "Embedded header include names for the compile task. This option can be "
163 "specified multiple times and has a one to one correspondence with "
164 "--input-headers.",
"STRING"},
165 {
"bin",
'b', 0, G_OPTION_ARG_FILENAME_ARRAY, &bin_files,
166 "Binary input file. This option can be specified multiple times.",
168 {
"output",
'o', 0, G_OPTION_ARG_FILENAME, &output,
169 "Binary output file.",
"FILE"},
170 {
"kernel-info",
'k', 0, G_OPTION_ARG_STRING_ARRAY, &kernel_names,
171 "Show information about the specified kernel. This option can be "
172 "specified multiple times.",
"STRING"},
173 {
"build-log",
'u', 0, G_OPTION_ARG_FILENAME, &bld_log_out,
174 "Save build log to the specified file. By default the build log is "
175 "printed to stderr.",
"FILE"},
176 {
"version", 0, 0, G_OPTION_ARG_NONE, &version,
177 "Output version information and exit.", NULL},
178 { NULL, 0, 0, 0, NULL, NULL, NULL }
191 g_return_if_fail(err == NULL || *err == NULL);
194 GOptionContext* context = NULL;
197 context = g_option_context_new(
" - " CCL_C_DESCRIPTION);
200 g_option_context_add_main_entries(context, entries, NULL);
203 g_option_context_parse(context, &argc, &argv, err);
207 g_assert(*err == NULL);
213 g_assert(*err != NULL);
218 if (context) g_option_context_free(context);
244 size_t k_pref_wg_size_mult;
245 size_t* k_compile_wg_size;
246 cl_ulong k_loc_mem_size;
247 cl_ulong k_priv_mem_size;
250 CCLErr* err_internal = NULL;
265 krnl, dev, CL_KERNEL_WORK_GROUP_SIZE,
size_t, &err_internal);
266 if (ccl_c_info_unavailable(err_internal)) {
267 g_clear_error(&err_internal);
268 g_printf(
" - Maximum workgroup size : N/A\n");
271 g_printf(
" - Maximum workgroup size : %lu\n",
272 (
unsigned long) k_wg_size);
277 if (ocl_ver >= 110) {
279 dev, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE,
280 size_t, &err_internal);
281 if (ccl_c_info_unavailable(err_internal)) {
282 g_clear_error(&err_internal);
283 g_printf(
" - Preferred multiple of workgroup size : N/A\n");
286 g_printf(
" - Preferred multiple of workgroup size : %lu\n",
287 (
unsigned long) k_pref_wg_size_mult);
293 CL_KERNEL_COMPILE_WORK_GROUP_SIZE,
size_t*, &err_internal);
294 if (ccl_c_info_unavailable(err_internal)) {
295 g_clear_error(&err_internal);
296 g_printf(
" - WG size in __attribute__ qualifier : N/A\n");
299 g_printf(
" - WG size in __attribute__ qualifier : "
301 (
unsigned long) k_compile_wg_size[0],
302 (
unsigned long) k_compile_wg_size[1],
303 (
unsigned long) k_compile_wg_size[2]);
308 CL_KERNEL_LOCAL_MEM_SIZE, cl_ulong, &err_internal);
309 if (ccl_c_info_unavailable(err_internal)) {
310 g_clear_error(&err_internal);
311 g_printf(
" - Local memory used by kernel : N/A\n");
314 g_printf(
" - Local memory used by kernel : %lu bytes\n",
315 (
unsigned long) k_loc_mem_size);
320 CL_KERNEL_PRIVATE_MEM_SIZE, cl_ulong, &err_internal);
321 if (ccl_c_info_unavailable(err_internal)) {
322 g_clear_error(&err_internal);
323 g_printf(
" - Min. private mem. used by each workitem : N/A\n");
326 g_printf(
" - Min. private mem. used by each workitem : %lu bytes\n",
327 (
unsigned long) k_priv_mem_size);
333 g_assert(err == NULL || *err == NULL);
339 g_assert(err == NULL || *err != NULL);
356 int main(
int argc,
char* argv[]) {
359 CCLErr* err = NULL, *err_build = NULL;
368 guint n_src_files, n_bin_files, n_src_h_files,
369 n_src_h_names, n_kernel_names;
387 GPtrArray* prgs = NULL;
390 cl_build_status build_status;
393 const char* build_status_str;
396 const char* build_log;
410 }
else if (opt_list) {
423 (src_h_files == NULL) && (bin_files == NULL),
425 "No source or binary input files have been specified.");
428 n_src_files = src_files != NULL ? g_strv_length(src_files) : 0;
429 n_bin_files = bin_files != NULL ? g_strv_length(bin_files) : 0;
430 n_src_h_files = src_h_files != NULL ? g_strv_length(src_h_files) : 0;
431 n_src_h_names = src_h_names != NULL ? g_strv_length(src_h_names) : 0;
432 n_kernel_names = kernel_names != NULL ? g_strv_length(kernel_names) : 0;
435 if (dev_idx == CCL_UTILS_NODEVICE) {
453 (n_src_files > 0) && (n_bin_files > 0),
455 "The 'build' task requires either: 1) one or more "
456 "source files; or, 2) one binary file.");
459 "The 'build' task accepts at most one binary file.");
463 (n_src_h_files > 0) || (n_src_h_names > 0),
465 "Input headers can only be specified for the 'compile' "
469 if (n_bin_files == 1) {
473 *bin_files, NULL, &err);
479 ctx, n_src_files, (
const char**) src_files, &err);
489 if (!ccl_c_is_build_error(err_build)) {
500 "The 'compile' task requires at least one source file.");
505 "The 'compile' task does not support binaries.");
510 (n_src_h_files != n_src_h_names) && (n_src_h_names > 0),
512 "Number of header include names must be the same as the "
513 "number of input headers.");
519 prgs = g_ptr_array_new_full(
524 for (i = 0; i < n_src_h_files; i++) {
528 1, (
const char**) &(src_h_files[i]), &err);
532 g_ptr_array_add(prgs, (gpointer) prg_aux);
539 n_src_files, (
const char**) src_files, &err);
546 (
const char**) (src_h_names ? src_h_names : src_h_files),
547 NULL, NULL, &err_build);
551 if (!ccl_c_is_build_error(err_build)) {
562 (n_src_files > 0) || (n_src_h_files > 0),
564 "The 'link' task requires at least one binary file "
565 "and does not support source files.");
568 prgs = g_ptr_array_new_full(
573 for (i = 0; i < n_bin_files; i++) {
577 bin_files[i], NULL, &err);
581 g_ptr_array_add(prgs, (gpointer) prg_aux);
587 n_bin_files, (
CCLProgram**) prgs->pdata, NULL,
591 if (!ccl_c_is_build_error(err_build)) {
606 g_printf(
"* Device : %s\n", dname);
613 CL_PROGRAM_BUILD_STATUS, cl_build_status, &err);
615 build_status_str = ccl_c_get_build_status_str(build_status);
621 build_status = CL_BUILD_NONE;
622 build_status_str =
"Unavailable";
627 g_printf(
"* Build status : %s\n", build_status_str);
630 if (output && prg && (build_status == CL_BUILD_SUCCESS)) {
634 g_printf(
"* Binary output file : %s\n", output);
640 g_printf(
"* Additional information : %s\n", err_build->message);
644 if (kernel_names && !err_build) {
647 for (i = 0; i < n_kernel_names; i++) {
650 g_printf(
"* Kernel information : %s\n", kernel_names[i]);
658 g_printf(
"* Build log :");
662 g_printf(
" Unavailable.\n");
671 g_info(
"Unable to retrieve build log. %s", err->message);
678 if ((build_log) && (strlen(build_log) > 0)) {
684 g_printf(
" Saved to %s.\n", bld_log_out);
685 g_file_set_contents(bld_log_out, build_log, -1, &err);
691 g_printf(
" Printed to error output stream.\n");
692 g_fprintf(stderr,
"\n%s\n", build_log);
699 g_printf(
" Empty.\n");
707 g_assert(err == NULL);
708 status = err_build ? EXIT_FAILURE : EXIT_SUCCESS;
714 g_assert(err != NULL);
717 g_fprintf(stderr,
"* Error : %s\n", err->message);
718 status = EXIT_FAILURE;
728 g_clear_error(&err_build);
729 if (src_files) g_strfreev(src_files);
730 if (src_h_files) g_strfreev(src_h_files);
731 if (src_h_names) g_strfreev(src_h_names);
732 if (kernel_names) g_strfreev(kernel_names);
733 if (bin_files) g_strfreev(bin_files);
734 if (options) g_free(options);
735 if (bld_log_out) g_free(bld_log_out);
736 if (output) g_free(output);
739 if (prgs) g_ptr_array_free(prgs, TRUE);
void ccl_context_destroy(CCLContext *ctx)
Decrements the reference count of the context wrapper object.
int main(int argc, char *argv[])
Kernel analyzer main program function.
const char * ccl_program_get_device_build_log(CCLProgram *prg, CCLDevice *dev, CCLErr **err)
Get build log for most recent build, compile or link for the specified device.
#define ccl_kernel_get_workgroup_info_scalar(krnl, dev, param_name, param_type, err)
Macro which returns a scalar kernel workgroup information value.
#define ccl_if_err_create_goto(err, quark, error_condition, error_code, label, msg,...)
If error is detected (error_code != no_error_code), create an error object (CCLErr) and go to the spe...
CCLProgram * ccl_program_new_from_binary_file(CCLContext *ctx, CCLDevice *dev, const char *filename, cl_int *binary_status, CCLErr **err)
Create a new program wrapper object from a file containing binary code executable on a specific devic...
void ccl_c_args_parse(int argc, char *argv[], CCLErr **err)
Parse and verify command line arguments.
The context wrapper class.
#define ccl_if_err_propagate_goto(err_dest, err_src, label)
Same as ccl_if_err_goto(), but rethrows error in a source CCLErr object to a new destination CCLErr o...
#define ccl_if_err_goto(err, label)
If error is detected in err object (err != NULL), go to the specified label.
CCLDevice * ccl_context_get_device(CCLContext *ctx, cl_uint index, CCLErr **err)
Get CCLDevice wrapper at given index.
cl_uint ccl_program_get_opencl_version(CCLProgram *prg, CCLErr **err)
Get the OpenCL version of the platform associated with this program.
void ccl_common_version_print(const char *exec_name)
Print executable version.
#define CCL_ERROR
Resolves to error category identifying string, in this case an error in cf4ocl.
cl_bool ccl_program_build(CCLProgram *prg, const char *options, CCLErr **err)
Utility function which builds (compiles and links) a program executable from the program source or bi...
Common header file for _cf4ocl utilities.
#define ccl_program_get_build_info_scalar(prg, dev, param_name, param_type, err)
Macro which returns a scalar program build information value.
#define ccl_context_new_from_menu(err)
Creates a context wrapper from a device selected by the user from a menu.
#define ccl_device_get_info_array(dev, param_name, param_type, err)
Macro which returns an array device information value.
Invalid function arguments.
CCLProgram * ccl_program_link(CCLContext *ctx, cl_uint num_devices, CCLDevice *const *devs, const char *options, cl_uint num_input_programs, CCLProgram **input_prgs, ccl_program_callback pfn_notify, void *user_data, CCLErr **err)
Link a set of compiled programs and create an executable program wrapper.
void ccl_c_kernel_info_show(CCLProgram *prg, CCLDevice *dev, const char *kernel, CCLErr **err)
Show kernel information.
CCLProgram * ccl_program_new_from_source_files(CCLContext *ctx, cl_uint count, const char **filenames, CCLErr **err)
Create a new program wrapper object from several source files.
cl_bool ccl_program_compile(CCLProgram *prg, cl_uint num_devices, CCLDevice *const *devs, const char *options, cl_uint num_input_headers, CCLProgram **prg_input_headers, const char **header_include_names, ccl_program_callback pfn_notify, void *user_data, CCLErr **err)
Compile a program's source code.
GError CCLErr
Error handling class.
cl_bool ccl_program_save_binary(CCLProgram *prg, CCLDevice *dev, const char *filename, CCLErr **err)
Save the program binary code for a specified device to a file.
void ccl_devsel_print_device_strings(CCLErr **err)
Print to stdout a device description string for each device in the system.
CCLKernel * ccl_program_get_kernel(CCLProgram *prg, const char *kernel_name, CCLErr **err)
Get the kernel wrapper object for the given program kernel function.
#define ccl_kernel_get_workgroup_info_array(krnl, dev, param_name, param_type, err)
Macro which returns an array kernel workgroup information value.
cl_bool ccl_wrapper_memcheck()
Debug function which checks if memory allocated by wrappers has been properly freed.
#define ccl_context_new_from_device_index(data, err)
Creates a context wrapper using a device selected by its index.
void ccl_program_destroy(CCLProgram *prg)
Decrements the reference count of the program wrapper object.