source: CIVL/examples/translation/openclversion2.15/square.cvl@ c2a3f74

1.23 2.0 acw/focus-triggers main test-branch
Last change on this file since c2a3f74 was fa007d5, checked in by Jacob Trieu <fuufusuu@…>, 12 years ago

new example in progress

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@1368 fb995dde-84ed-4084-dfe6-e5aef3e2452c

  • Property mode set to 100644
File size: 8.8 KB
Line 
1//Forget the program
2
3#include "cl.cvl"
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <civlc.h>
8
9$input int NUM_DEVICES;
10$input int MAX_NUM_DEVICES;
11$assume 0 < NUM_DEVICES && NUM_DEVICES < MAX_NUM_DEVICES;
12
13$input int DATA_SIZE;
14$input int MAX_DATA_SIZE;
15$assume 0 < DATA_SIZE && DATA_SIZE < MAX_NUM_DEVICES;
16
17$input int LOCAL;
18$input int MAX_LOCAL;
19$assume 0 < LOCAL && LOCAL < MAX_LOCAL;
20//this args struct will hold all the parameters of for the kernel function
21typedef struct
22{
23 //Variables for kernels
24 /*
25 float * input;
26 float * output;
27 int count;
28
29 void * input;
30 void * output;
31 void * count;
32 */
33 void * param[3];
34
35}args;
36
37/*
38 args * argument - Takes in the struct, which is changed for every program using a different kernel
39*/
40cl_kernel clCreateKernel(args * argument, char * function)
41{
42 cl_kernel kernel;
43 kernel.arguments = argument;
44 kernel.method = function;
45
46 return kernel;
47}
48
49void clReleaseKernel(cl_kernel kernel)
50{
51 for (int i = 0; i < 3; i++)
52 {
53 free(((args*)kernel.arguments)->param[i]);
54 }
55}
56
57/*
58 This is the kernel that processes compute with
59 int workgroup - Gives the workgroup that a particular process came from, made by clEnqueueNDRangeKernel
60 int global_id - Gives the global_id that a particular process has, given by workfunc
61 int local_id - Gives the local_id that a particular process has, given by workfunc
62 float* input - Kernel argument
63 float* output - Kernel argument
64 int count - Kernel argument
65*/
66void square(int workgroup, int global_id, int local_id, float* input, float* output, int count)
67{
68 //int i = get_global_id(0);
69 int i = global_id;
70 if (i < count)
71 {
72 output[i] = input[i] * input[i];
73 //printf("output[%d] is %d\n", i, output[i]);
74 }
75}
76/*
77 workfunc assigns local and global ids, before calling the kernel.
78 Note: The function should be identical in all transformations except the calling of the kernel, which means that it cannot be in openCLshared.cvl
79 size_t local - The size of the workgroups, used to calculate blocks
80 size_t global - The total amount of work to be done
81 cl_kernel param - Holds the data for local_id, global_id, and the workgroup
82 Use the print statement to get a better idea of what it means to split workgroups, local_ids, and global_ids
83*/
84void empty()
85{
86}
87
88void workfunc(size_t local, size_t global, cl_kernel param)
89{
90 $proc procs[local];
91 for(int i = local * param.workgroup; i < local * param.workgroup + local; i++)
92 {
93 int count = *(int*)(((args*)param.arguments)->param[2]);
94 param.local_id = i % local;
95 param.global_id = i;
96 printf("My workgroup id is %d, my global id is %d, my local id is %d, and my method is %s\n", param.workgroup, param.global_id, param.local_id, param.method);
97
98 procs[param.local_id] = $spawn square(param.workgroup, param.global_id, param.local_id, ((args*)param.arguments)->param[0], ((args*)param.arguments)->param[1], count);
99
100 }
101 for(int j = 0; j < local; j++)
102 {
103 $wait(procs[j]);
104 }
105}
106
107/*
108 Splits up and spawns processes based on global and local, using block
109 TODO: remove cl_command_queue completely and put into a "just in case" file, currently not needed
110 cl_command_queue commands - Holds a queue of the order that devices are to be executed
111 cl_kernel kernel - Holds all the arguments for the kernel, as well as local_id, global_id, and the workgroup
112 size_t global - The total amount of work to be done
113 size_t local - Number to split into workgroups by
114*/
115int clEnqueueNDRangeKernel(cl_kernel kernel, size_t global, size_t local)
116{
117
118 $assert(global % local == 0);
119 int numworkgroups = global/local;
120 cl_kernel param[numworkgroups];
121 $proc procs[numworkgroups];
122 //consider $parfor
123
124 /*
125 $domain(1) dom = {0 .. numworkgroups - 1};
126
127 $for(int i: dom)
128 {
129 param[i] = kernel;
130 param[i].workgroup = i;
131 }
132 $parfor(int i: dom)
133 {
134 workfunc(local, global, param[i]);
135 }
136 */
137
138 for(int i = 0; i < global/local; i++)
139 {
140 param[i] = kernel;
141 param[i].workgroup = i;
142 procs[i] = $spawn workfunc(local, global, param[i]);
143 }
144
145 //this part here is the new clFinish(commands);
146 for(int i = 0; i < global/local; i++)
147 {
148 $wait(procs[i]);
149 }
150
151 return CL_SUCCESS;
152
153}
154
155
156int main(int argc, char** argv)
157{
158 //Make function pointers for every method
159 void (*squarePtr) (int, int, int, float *, float *, int);
160 squarePtr = &square;
161
162 args * arguments;
163 arguments = (args*)malloc(sizeof(args));
164
165 float data[DATA_SIZE]; // original data set given to device
166 float results[DATA_SIZE]; // results returned from device
167 unsigned int correct; // number of correct results returned
168
169 size_t global; // global domain size for our calculation
170 size_t local; // local domain size for our calculation
171
172 cl_device_id device_id; // compute device id
173 cl_context context; // compute context
174 cl_command_queue commands; // compute command queue
175 //cl_program program; // compute program
176 cl_kernel kernel; // compute kernel
177 int err;
178
179 float * input; // device memory used for the input array
180 float * output; // device memory used for the output array
181
182 //Puts in data for input
183 unsigned int count = DATA_SIZE;
184 for(int i = 0; i < count; i++)
185 {
186 data[i] = i;
187 }
188
189
190 //clCreateProgram is far different from the real version, this just stores parameters for the kernel
191 //In order to make this clear, it is clCreateProgram and not something like clCreateProgramFromSource, which actually exists in openCL code
192 //program = clCreateProgram(arguments);
193
194 kernel = clCreateKernel(arguments, "square");
195
196 //replaces clCreateBuffer
197 input = (float *) malloc(sizeof(float) * count);
198 output = (float *) malloc(sizeof(float) * count);
199
200
201 //replaces clEnqueueWriteBuffer, puts data into the input to be put into the kernel arguments
202 memcpy(input, data, sizeof(float) * count);
203
204 /*
205 err = 0;
206 err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &input);
207 err = clSetKernelArg(kernel, 1, sizeof(cl_mem), &output);
208 err = clSetKernelArg(kernel, 2, sizeof(unsigned int), &count);
209 */
210 /*
211 Possible current implementation:
212 clSetKernelArg(cl_kernel, index, sizeof(...), data to put in, int (picks global 0, local 1 , group 2), bool (for if it was already a pointer));
213 Example:
214 clSetKernelArg(kernel, 0, sizeof(float) * count, 0, true);
215
216 This raises a question, how does OpenCL know how to do this without using the last two parameters?
217 */
218
219 //use pointer instead of malloc + memcpy for global variables
220 //((args*)kernel.arguments)->input = (float*)malloc(sizeof(float) * count);
221 //memcpy(((args *)kernel.arguments)->input, input, sizeof(float) * count);
222
223 ((args*)kernel.arguments)->param[0] = input;
224
225 //((args*)kernel.arguments)->output = (float*)malloc(sizeof(float) * count);
226 //memcpy(((args*)kernel.arguments)->output, output, sizeof(float));
227
228 ((args*)kernel.arguments)->param[1] = output;
229
230 ((args*)kernel.arguments)->param[2] = (int *)malloc(sizeof(int));
231 memcpy(((args*)kernel.arguments)->param[2], &count, sizeof(int));
232 //no malloc needed for non pointers
233 //if this were global then there would be a pointer of count instead of a malloc
234
235 //clGetKernelWorkGroupInfo would get a local size optimal for a device, but is not needed here
236 local = LOCAL;
237
238 global = count;
239 /*
240 commands holds the "order" of devices
241 kernel holds program, which holds variables
242 offset not implemented
243 */
244 err = clEnqueueNDRangeKernel(kernel, global, local);
245
246 //Replaces clEnqueueReadBuffer, which takes one of the saved variables and puts it out to another one
247 memcpy(results, output, sizeof(float) * count);
248
249 //verifies that all values in results are actually squared
250 correct = 0;
251 for(int i = 0; i < count; i++)
252 {
253 if(results[i] == data[i] * data[i])
254 {
255 correct++;
256 }
257 }
258 printf("Computed '%d/%d' correct values!\n", correct, count);
259
260 //TODO: Think of using void * array instead of regular arguments to make freeing easier
261 clReleaseKernel(kernel);
262 free(arguments);
263
264
265 return 0;
266}
267/*Note, pointers to global memory cannot be stored in local memory
268support for global, local, constant and group, local being the default
269private (local) - variable assignment, or malloc + memcpy
270
271global - pointer with memory location. For regular non pointer variables, make a pointer and assign it to it, then use the pointer
272Global variables can be declared in program source but they must use the "constant" address space qualifier and need to be initialized.
273You cannot have global variables that can be modified by kernels and where the modified values are persistent across work-groups and kernel executions.
274For this, you should use memory objects instead.
275
276Constant is just like global, but read only
277
278group - ???
279*/
280
281
Note: See TracBrowser for help on using the repository browser.