You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
std::cout << "Using device: " << name << std::endl;
73
+
74
+
// 3. Create an OpenCL context and command queue on that device
75
+
// the context is like a container for all OpenCL objects (buffers, programs, kernels, etc.) associated with the device
76
+
// the queue is used to submit work (kernel executions, memory transfers, etc.) to the device
77
+
// operations must be done through the command queue
78
+
cl_int err;
79
+
cl_context ctx = clCreateContext(NULL, 1, &dev, NULL, NULL, &err); // properties, num_devices, array of device ids (dev), call back for errors, user data for call back, error code
constchar* csrc = src.c_str(); // convert it to C-style character array
97
+
size_t len = src.size();
98
+
// create the program object from the source code string
99
+
cl_program program = clCreateProgramWithSource(ctx, 1, &csrc, &len, &err); // context, number of strings, array of strings, array of string lengths, error code
100
+
CHECK(err);
101
+
102
+
// build the program object
103
+
err = clBuildProgram(program, 1, &dev, NULL, NULL, NULL); // program, num_devices, array of device ids, build options, call back, user data
104
+
if (err != CL_SUCCESS) { // if that fails, get and print the build log
// 6. Create device buffers and transfer input data to the device
118
+
// buffers are memory allocations on the device that can be read from and written to by kernels
119
+
// openCL defines three memory types: buffer, image, and pipe
120
+
// buffer stores contiguous linear data (like arrays/vectors/matrices) and can be accessed on the device using pointers, created using clCreateBuffer
121
+
// image is optimized for 2D/3D data and provides built-in functions for sampling and filtering (used in graphics/vision applications)
122
+
// pipe is used for streaming data between kernels
123
+
// here we use buffer memory type to create buffers for our input/output vectors
124
+
125
+
// make three buffers: two for input vectors and one for output vector, fill the input buffers with data (host)
126
+
size_t bytes = N*sizeof(float);
127
+
std::vector<float> A(N), B(N), C(N);
128
+
for(int i=0;i<N;i++){
129
+
A[i] = i;
130
+
B[i] = 2*i;
131
+
}
132
+
133
+
// create device buffers and copy input data from host to device
134
+
// note bitwise or operator (|) is used to combine multiple memory flags
135
+
cl_mem dA = clCreateBuffer(ctx, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, bytes, A.data(), &err); // context, flags, size in bytes, host pointer (data to copy), error code
136
+
CHECK(err);
137
+
cl_mem dB = clCreateBuffer(ctx, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, bytes, B.data(), &err);
138
+
CHECK(err);
139
+
cl_mem dC = clCreateBuffer(ctx, CL_MEM_WRITE_ONLY, bytes, NULL, &err);
140
+
CHECK(err);
141
+
142
+
// 7. Set kernel arguments as the buffers created above
143
+
clSetKernelArg(kernel, 0, sizeof(cl_mem), &dA); // kernel, argument index, size of argument, pointer to argument value
144
+
clSetKernelArg(kernel, 1, sizeof(cl_mem), &dB);
145
+
clSetKernelArg(kernel, 2, sizeof(cl_mem), &dC);
146
+
clSetKernelArg(kernel, 3, sizeof(int), &N);
147
+
148
+
// 8. Kernel execution
149
+
// specify the global and local work sizes. Global work size is total number of work items (threads) to execute the kernel
150
+
// local work size is number of work items in a work group (like CUDA blocks), just a way to organize work items for better performance
151
+
// 256 is a common choice for local work size
152
+
size_t global = N;
153
+
size_t local = 256;
154
+
155
+
auto start = std::chrono::high_resolution_clock::now(); // start timer for benchmarking
156
+
CHECK(clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &global, &local, 0, NULL, NULL)); // command queue, kernel, work dimension, global work offset, global work size, local work size, num events in wait list, event wait list, event
157
+
clFinish(queue); // wait for all commands in the queue to finish
158
+
auto end = std::chrono::high_resolution_clock::now(); // end timer
159
+
160
+
double ms = std::chrono::duration<double, std::milli>(end-start).count();
161
+
std::cout << "Time: " << ms << " ms\n"; // print elapsed time
162
+
163
+
// read back the result from device to host, queue, buffer, blocking read, offset, size, host pointer, num events in wait list, event wait list, event
0 commit comments