Skip to content

Commit a2af3f8

Browse files
committed
vec_io can also take binary!
1 parent 5e2bd82 commit a2af3f8

File tree

4 files changed

+94
-54
lines changed

4 files changed

+94
-54
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ main
2626
*.tmp
2727
tmp.*
2828
tmp
29+
*.bak
2930

3031
core
3132
core.*

opencl/binary_shader.c

Lines changed: 8 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
/*Let's play with clCreateProgramWithBinary.
1+
/*
2+
Let's play with clCreateProgramWithBinary.
23
34
Compile the "inc.cl" CL C shader to binary, save the binary to a file, and load the shader from the binary:
45
@@ -17,22 +18,15 @@ just dumps PTX human readable assembly, which we can modify without
1718
reverse engineering. Hurray!
1819
*/
1920

20-
#define BIN_PATH __FILE__ ".bin.tmp"
21-
2221
#include "common.h"
2322

2423
int main(int argc, char **argv) {
2524
Common common;
26-
FILE *f;
27-
char *binary, *source_path;
28-
cl_int input[] = {1, 2}, errcode_ret, binary_status;
29-
cl_kernel kernel;
25+
char *source_path;
26+
cl_int input[] = {1, 2};
3027
cl_mem buffer;
31-
cl_program program;
3228
const size_t global_work_size = sizeof(input) / sizeof(input[0]);
3329
int use_cache;
34-
long lenght;
35-
size_t binary_size;
3630

3731
if (argc > 1) {
3832
use_cache = !strcmp(argv[1], "0");
@@ -45,37 +39,13 @@ int main(int argc, char **argv) {
4539
source_path = "inc.cl";
4640
}
4741

48-
/* Get the binary, and create a kernel with it. */
49-
if (use_cache) {
50-
common_init(&common, NULL);
51-
binary = common_read_file(BIN_PATH, &lenght);
52-
binary_size = lenght;
53-
} else {
54-
common_init_file(&common, source_path);
55-
clGetProgramInfo(common.program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binary_size, NULL);
56-
binary = malloc(binary_size);
57-
clGetProgramInfo(common.program, CL_PROGRAM_BINARIES, binary_size, &binary, NULL);
58-
f = fopen(BIN_PATH, "w");
59-
fwrite(binary, binary_size, 1, f);
60-
fclose(f);
61-
}
62-
program = clCreateProgramWithBinary(
63-
common.context, 1, &common.device, &binary_size,
64-
(const unsigned char **)&binary, &binary_status, &errcode_ret
65-
);
66-
assert(NULL != program);
67-
common_assert_success(binary_status);
68-
common_assert_success(errcode_ret);
69-
free(binary);
70-
common_build_program(&common, NULL, &program);
71-
kernel = clCreateKernel(program, "kmain", &errcode_ret);
72-
assert(NULL != kernel);
73-
common_assert_success(errcode_ret);
42+
/* Create binary or kernel from binary. */
43+
common_create_kernel_or_use_cache(&common, use_cache, source_path, __FILE__ ".bin.tmp");
7444

7545
/* Run the kernel created from the binary. */
7646
buffer = clCreateBuffer(common.context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, sizeof(input), input, NULL);
77-
clSetKernelArg(kernel, 0, sizeof(buffer), &buffer);
78-
clEnqueueNDRangeKernel(common.command_queue, kernel, 1, NULL, &global_work_size, NULL, 0, NULL, NULL);
47+
clSetKernelArg(common.kernel, 0, sizeof(buffer), &buffer);
48+
clEnqueueNDRangeKernel(common.command_queue, common.kernel, 1, NULL, &global_work_size, NULL, 0, NULL, NULL);
7949
clFlush(common.command_queue);
8050
clFinish(common.command_queue);
8151
clEnqueueReadBuffer(common.command_queue, buffer, CL_TRUE, 0, sizeof(input), input, 0, NULL, NULL);
@@ -85,8 +55,6 @@ int main(int argc, char **argv) {
8555
assert(input[1] == 3);
8656

8757
/* Cleanup. */
88-
clReleaseKernel(kernel);
89-
clReleaseProgram(program);
9058
clReleaseMemObject(buffer);
9159
common_deinit(&common);
9260
return EXIT_SUCCESS;

opencl/common.h

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ void common_create_kernel_file(
112112
free(source);
113113
}
114114

115+
/*
116+
* @param[in] source: if NULL, kernel and program are left to NULL on common
117+
**/
115118
void common_init_options(
116119
Common *common,
117120
const char *source,
@@ -151,22 +154,71 @@ void common_init_file(
151154
common_init_file_options(common, source_path, "");
152155
}
153156

157+
void common_deinit_kernel_and_program(cl_kernel kernel, cl_program program) {
158+
if (NULL != kernel) {
159+
clReleaseKernel(kernel);
160+
}
161+
if (NULL != program) {
162+
clReleaseProgram(program);
163+
}
164+
}
165+
154166
void common_deinit(
155167
Common *common
156168
) {
157169
clReleaseCommandQueue(common->command_queue);
158-
clReleaseProgram(common->program);
159-
if (NULL != common->kernel) {
160-
clReleaseKernel(common->kernel);
161-
}
162-
if (NULL != common->context) {
163-
clReleaseContext(common->context);
164-
}
170+
common_deinit_kernel_and_program(common->kernel, common->program);
171+
clReleaseContext(common->context);
165172
#ifdef CL_1_2
166173
clReleaseDevice(common->device);
167174
#endif
168175
}
169176

177+
void common_create_kernel_or_use_cache(
178+
Common *common,
179+
int use_cache,
180+
char *source_path,
181+
char *bin_path
182+
) {
183+
FILE *f;
184+
char *binary;
185+
cl_int errcode_ret, binary_status;
186+
cl_kernel kernel;
187+
cl_program program;
188+
long length;
189+
size_t binary_size;
190+
191+
if (use_cache) {
192+
common_init(common, NULL);
193+
binary = common_read_file(bin_path, &length);
194+
binary_size = length;
195+
} else {
196+
common_init_file(common, source_path);
197+
clGetProgramInfo(common->program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binary_size, NULL);
198+
binary = malloc(binary_size);
199+
clGetProgramInfo(common->program, CL_PROGRAM_BINARIES, binary_size, &binary, NULL);
200+
f = fopen(bin_path, "w");
201+
fwrite(binary, binary_size, 1, f);
202+
fclose(f);
203+
}
204+
program = clCreateProgramWithBinary(
205+
common->context, 1, &common->device, &binary_size,
206+
(const unsigned char **)&binary, &binary_status, &errcode_ret
207+
);
208+
assert(NULL != program);
209+
common_assert_success(binary_status);
210+
common_assert_success(errcode_ret);
211+
free(binary);
212+
common_build_program(common, NULL, &program);
213+
kernel = clCreateKernel(program, "kmain", &errcode_ret);
214+
assert(NULL != kernel);
215+
common_assert_success(errcode_ret);
216+
/* Cleanup kernel and program if they were created from source. */
217+
common_deinit_kernel_and_program(common->kernel, common->program);
218+
common->kernel = kernel;
219+
common->program = program;
220+
}
221+
170222
double common_get_nanos(void) {
171223
struct timespec ts;
172224
timespec_get(&ts, TIME_UTC);

opencl/interactive/vec_io.c

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
/*
2+
Process an arbitrary input vector with a given shader and print output to stdout.
3+
24
Sample usage:
35
46
echo '1 2 3' | tr ' ' '\n' >vec_io.vec
57
./prog vec_io.cl vec_io.vec
68
9+
Output:
10+
11+
2.000000e+00
12+
3.000000e+00
13+
4.000000e+00
14+
715
Or you can use the default kernel and stdin input:
816
917
echo '1 2 3' | tr ' ' '\n' | ./prog
@@ -12,6 +20,13 @@ Set global work size and work group size different than defaults (n and 1):
1220
1321
./prog -g 10 -l 5 vec_io.cl vec_io.vec
1422
23+
Generate a binary shader , and then use it (clCreateProgramWithBinary) instead of the CL C:
24+
25+
./prog vec_io.cl vec_io.vec
26+
./prog -b vec_io.c.bin.tmp vec_io.vec
27+
28+
This allows you to modify the binary shader while reverse engineer it.
29+
1530
Generic boilerplate that:
1631
1732
- takes a vector as input either from stdin or from a file, one per line
@@ -28,21 +43,25 @@ to parse clinfo and get those values out... hmmm...
2843
#include "common.h"
2944

3045
int main(int argc, char **argv) {
31-
char *cl_source_path;
46+
char *source_path;
3247
cl_float *io;
3348
cl_mem buffer;
3449
Common common;
3550
FILE *input_vector_file;
3651
float f;
37-
int a, global_work_size_given;
52+
int a, global_work_size_given, use_cache;
3853
size_t i, global_work_size, local_work_size, n, nmax, io_sizeof;
3954

4055
/* Treat CLI arguments. */
4156
global_work_size_given = 0;
4257
local_work_size = 1;
58+
use_cache = 0;
4359
for (a = 1; a < argc; ++a) {
4460
if (argv[a][0] == '-') {
4561
switch(argv[a][1]) {
62+
case 'b':
63+
use_cache = 1;
64+
break;
4665
case 'g':
4766
a++;
4867
global_work_size = strtoul(argv[a], NULL, 10);
@@ -58,9 +77,9 @@ int main(int argc, char **argv) {
5877
}
5978
}
6079
if (argc > a) {
61-
cl_source_path = argv[a];
80+
source_path = argv[a];
6281
} else {
63-
cl_source_path = "vec_io.cl";
82+
source_path = "vec_io.cl";
6483
}
6584
a++;
6685
if (argc > a) {
@@ -86,8 +105,8 @@ int main(int argc, char **argv) {
86105
global_work_size = n;
87106
}
88107

89-
/* Run kernel. */
90-
common_init_file(&common, cl_source_path);
108+
/* Create kernel. */
109+
common_create_kernel_or_use_cache(&common, use_cache, source_path, __FILE__ ".bin.tmp");
91110
buffer = clCreateBuffer(common.context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, io_sizeof, io, NULL);
92111
clSetKernelArg(common.kernel, 0, sizeof(buffer), &buffer);
93112
clEnqueueNDRangeKernel(common.command_queue, common.kernel, 1, NULL, &global_work_size, &local_work_size, 0, NULL, NULL);
@@ -97,7 +116,7 @@ int main(int argc, char **argv) {
97116

98117
/* Print result. */
99118
for (i = 0; i < n; ++i) {
100-
printf("%f\n", io[i]);
119+
printf("%.6e\n", io[i]);
101120
}
102121

103122
/* Cleanup. */

0 commit comments

Comments
 (0)