1 //
2 // Copyright (c) 2017 The Khronos Group Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 #include "common.h"
17
18 // Creates linked list using host code
create_linked_lists_on_host(cl_command_queue cmdq,cl_mem nodes,Node * pNodes2,cl_int ListLength,size_t numLists,cl_bool useNewAPI)19 cl_int create_linked_lists_on_host(cl_command_queue cmdq, cl_mem nodes, Node *pNodes2, cl_int ListLength, size_t numLists, cl_bool useNewAPI )
20 {
21 cl_int error = CL_SUCCESS;
22
23 log_info("SVM: creating linked list on host ");
24
25 Node *pNodes;
26 if (useNewAPI == CL_FALSE)
27 {
28 pNodes = (Node*) clEnqueueMapBuffer(cmdq, nodes, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, sizeof(Node)*ListLength*numLists, 0, NULL,NULL, &error);
29 test_error2(error, pNodes, "clEnqMapBuffer failed");
30 }
31 else
32 {
33 pNodes = pNodes2;
34 error = clEnqueueSVMMap(cmdq, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, pNodes2, sizeof(Node)*ListLength*numLists, 0, NULL,NULL);
35 test_error2(error, pNodes, "clEnqueueSVMMap failed");
36 }
37
38 create_linked_lists(pNodes, numLists, ListLength);
39
40 if (useNewAPI == CL_FALSE)
41 {
42 error = clEnqueueUnmapMemObject(cmdq, nodes, pNodes, 0,NULL,NULL);
43 test_error(error, "clEnqueueUnmapMemObject failed.");
44 }
45 else
46 {
47 error = clEnqueueSVMUnmap(cmdq, pNodes2, 0, NULL, NULL);
48 test_error(error, "clEnqueueSVMUnmap failed.");
49 }
50
51 error = clFinish(cmdq);
52 test_error(error, "clFinish failed.");
53 return error;
54 }
55
56 // Purpose: uses host code to verify correctness of the linked list
verify_linked_lists_on_host(int ci,cl_command_queue cmdq,cl_mem nodes,Node * pNodes2,cl_int ListLength,size_t numLists,cl_bool useNewAPI)57 cl_int verify_linked_lists_on_host(int ci, cl_command_queue cmdq, cl_mem nodes, Node *pNodes2, cl_int ListLength, size_t numLists, cl_bool useNewAPI )
58 {
59 cl_int error = CL_SUCCESS;
60
61 Node *pNodes;
62 if (useNewAPI == CL_FALSE)
63 {
64 pNodes = (Node*) clEnqueueMapBuffer(cmdq, nodes, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, sizeof(Node)*ListLength * numLists, 0, NULL,NULL, &error);
65 test_error2(error, pNodes, "clEnqueueMapBuffer failed");
66 }
67 else
68 {
69 pNodes = pNodes2;
70 error = clEnqueueSVMMap(cmdq, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, pNodes2, sizeof(Node)*ListLength * numLists, 0, NULL,NULL);
71 test_error2(error, pNodes, "clEnqueueSVMMap failed");
72 }
73
74 error = verify_linked_lists(pNodes, numLists, ListLength);
75 if(error) return -1;
76
77 if (useNewAPI == CL_FALSE)
78 {
79 error = clEnqueueUnmapMemObject(cmdq, nodes, pNodes, 0,NULL,NULL);
80 test_error(error, "clEnqueueUnmapMemObject failed.");
81 }
82 else
83 {
84 error = clEnqueueSVMUnmap(cmdq, pNodes2, 0,NULL,NULL);
85 test_error(error, "clEnqueueSVMUnmap failed.");
86 }
87
88 error = clFinish(cmdq);
89 test_error(error, "clFinish failed.");
90 return error;
91 }
92
create_linked_lists_on_device(int ci,cl_command_queue cmdq,cl_mem allocator,cl_kernel kernel_create_lists,size_t numLists)93 cl_int create_linked_lists_on_device(int ci, cl_command_queue cmdq, cl_mem allocator, cl_kernel kernel_create_lists, size_t numLists )
94 {
95 cl_int error = CL_SUCCESS;
96 log_info("SVM: creating linked list on device: %d ", ci);
97
98 size_t *pAllocator = (size_t *)clEnqueueMapBuffer(
99 cmdq, allocator, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, sizeof(size_t),
100 0, NULL, NULL, &error);
101 test_error2(error, pAllocator, "clEnqueueMapBuffer failed");
102 // reset allocator index
103 *pAllocator = numLists; // the first numLists elements of the nodes array are already allocated (they hold the head of each list).
104 error = clEnqueueUnmapMemObject(cmdq, allocator, pAllocator, 0,NULL,NULL);
105 test_error(error, " clEnqueueUnmapMemObject failed.");
106
107 error = clEnqueueNDRangeKernel(cmdq, kernel_create_lists, 1, NULL, &numLists, NULL, 0, NULL, NULL);
108 test_error(error, "clEnqueueNDRange failed.");
109 error = clFinish(cmdq);
110 test_error(error, "clFinish failed.");
111
112 return error;
113 }
114
verify_linked_lists_on_device(int vi,cl_command_queue cmdq,cl_mem num_correct,cl_kernel kernel_verify_lists,cl_int ListLength,size_t numLists)115 cl_int verify_linked_lists_on_device(int vi, cl_command_queue cmdq,cl_mem num_correct, cl_kernel kernel_verify_lists, cl_int ListLength, size_t numLists )
116 {
117 cl_int error = CL_SUCCESS;
118
119 log_info(" and verifying on device: %d ", vi);
120
121 cl_int *pNumCorrect = (cl_int*) clEnqueueMapBuffer(cmdq, num_correct, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, sizeof(cl_int), 0, NULL,NULL, &error);
122 test_error2(error, pNumCorrect, "clEnqueueMapBuffer failed");
123
124 *pNumCorrect = 0; // reset numCorrect to zero
125
126 error = clEnqueueUnmapMemObject(cmdq, num_correct, pNumCorrect, 0,NULL,NULL);
127 test_error(error, "clEnqueueUnmapMemObject failed.");
128
129 error = clEnqueueNDRangeKernel(cmdq, kernel_verify_lists, 1, NULL, &numLists, NULL, 0, NULL, NULL);
130 test_error(error,"clEnqueueNDRangeKernel failed");
131
132 pNumCorrect = (cl_int*) clEnqueueMapBuffer(cmdq, num_correct, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, sizeof(cl_int), 0, NULL,NULL, &error);
133 test_error2(error, pNumCorrect, "clEnqueueMapBuffer failed");
134 cl_int correct_count = *pNumCorrect;
135 error = clEnqueueUnmapMemObject(cmdq, num_correct, pNumCorrect, 0,NULL,NULL);
136 test_error(error, "clEnqueueUnmapMemObject failed");
137 clFinish(cmdq);
138 test_error(error,"clFinish failed");
139
140 if(correct_count != ListLength * (cl_uint)numLists)
141 {
142 error = -1;
143 log_info("Failed\n");
144 }
145 else
146 log_info("Passed\n");
147
148 return error;
149 }
150
151 // This tests that all devices and the host share a common address space; using only the coarse-grain features.
152 // This is done by creating a linked list on a device and then verifying the correctness of the list
153 // on another device or the host. This basic test is performed for all combinations of devices and the host that exist within
154 // the platform. The test passes only if every combination passes.
shared_address_space_coarse_grain(cl_device_id deviceID,cl_context context2,cl_command_queue queue,int num_elements,cl_bool useNewAPI)155 int shared_address_space_coarse_grain(cl_device_id deviceID, cl_context context2, cl_command_queue queue, int num_elements, cl_bool useNewAPI)
156 {
157 clContextWrapper context = NULL;
158 clProgramWrapper program = NULL;
159 cl_uint num_devices = 0;
160 cl_int error = CL_SUCCESS;
161 clCommandQueueWrapper queues[MAXQ];
162
163 error = create_cl_objects(deviceID, &linked_list_create_and_verify_kernels[0], &context, &program, &queues[0], &num_devices, CL_DEVICE_SVM_COARSE_GRAIN_BUFFER);
164 if(error) return -1;
165
166 size_t numLists = num_elements;
167 cl_int ListLength = 32;
168
169 clKernelWrapper kernel_create_lists = clCreateKernel(program, "create_linked_lists", &error);
170 test_error(error, "clCreateKernel failed");
171
172 clKernelWrapper kernel_verify_lists = clCreateKernel(program, "verify_linked_lists", &error);
173 test_error(error, "clCreateKernel failed");
174
175 // this buffer holds the linked list nodes.
176 Node* pNodes = (Node*) clSVMAlloc(context, CL_MEM_READ_WRITE, sizeof(Node)*ListLength*numLists, 0);
177
178 {
179 cl_bool usesSVMpointer = CL_FALSE;
180 clMemWrapper nodes;
181 if (useNewAPI == CL_FALSE)
182 {
183 nodes = clCreateBuffer(context, CL_MEM_USE_HOST_PTR, sizeof(Node)*ListLength*numLists, pNodes, &error);
184 test_error(error, "clCreateBuffer failed.");
185
186 // verify if buffer uses SVM pointer
187 size_t paramSize = 0;
188 error = clGetMemObjectInfo(nodes, CL_MEM_USES_SVM_POINTER, 0, 0, ¶mSize);
189 test_error(error, "clGetMemObjectInfo failed.");
190
191 if (paramSize != sizeof(cl_bool))
192 {
193 log_error("clGetMemObjectInfo(CL_MEM_USES_SVM_POINTER) returned wrong size.");
194 return -1;
195 }
196
197 error = clGetMemObjectInfo(nodes, CL_MEM_USES_SVM_POINTER, sizeof(cl_bool), &usesSVMpointer, 0);
198 test_error(error, "clGetMemObjectInfo failed.");
199
200 if (usesSVMpointer != CL_TRUE)
201 {
202 log_error("clGetMemObjectInfo(CL_MEM_USES_SVM_POINTER) returned CL_FALSE for buffer created from SVM pointer.");
203 return -1;
204 }
205 }
206
207 // this buffer holds an index into the nodes buffer, it is used for node allocation
208 clMemWrapper allocator = clCreateBuffer(context, CL_MEM_READ_WRITE,
209 sizeof(size_t), NULL, &error);
210
211 test_error(error, "clCreateBuffer failed.");
212
213 error = clGetMemObjectInfo(allocator, CL_MEM_USES_SVM_POINTER, sizeof(cl_bool), &usesSVMpointer, 0);
214 test_error(error, "clGetMemObjectInfo failed.");
215
216 if (usesSVMpointer != CL_FALSE)
217 {
218 log_error("clGetMemObjectInfo(CL_MEM_USES_SVM_POINTER) returned CL_TRUE for non-SVM buffer.");
219 return -1;
220 }
221
222 // this buffer holds the count of correct nodes, which is computed by the verify kernel.
223 clMemWrapper num_correct = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(cl_int), NULL, &error);
224 test_error(error, "clCreateBuffer failed.");
225
226 if (useNewAPI == CL_TRUE)
227 error |= clSetKernelArgSVMPointer(kernel_create_lists, 0, pNodes);
228 else
229 error |= clSetKernelArg(kernel_create_lists, 0, sizeof(void*), (void *) &nodes);
230
231 error |= clSetKernelArg(kernel_create_lists, 1, sizeof(void*), (void *) &allocator);
232 error |= clSetKernelArg(kernel_create_lists, 2, sizeof(cl_int), (void *) &ListLength);
233
234 error |= clSetKernelArgSVMPointer(kernel_verify_lists, 0, pNodes);
235 error |= clSetKernelArg(kernel_verify_lists, 1, sizeof(void*), (void *) &num_correct);
236 error |= clSetKernelArg(kernel_verify_lists, 2, sizeof(cl_int), (void *) &ListLength);
237 test_error(error, "clSetKernelArg failed");
238
239 // Create linked list on one device and verify on another device (or the host).
240 // Do this for all possible combinations of devices and host within the platform.
241 for (int ci=0; ci<(int)num_devices+1; ci++) // ci is CreationIndex, index of device/q to create linked list on
242 {
243 for (int vi=0; vi<(int)num_devices+1; vi++) // vi is VerificationIndex, index of device/q to verify linked list on
244 {
245 if(ci == num_devices) // last device index represents the host, note the num_device+1 above.
246 {
247 error = create_linked_lists_on_host(queues[0], nodes, pNodes, ListLength, numLists, useNewAPI);
248 if(error) return -1;
249 }
250 else
251 {
252 error = create_linked_lists_on_device(ci, queues[ci], allocator, kernel_create_lists, numLists);
253 if(error) return -1;
254 }
255
256 if(vi == num_devices)
257 {
258 error = verify_linked_lists_on_host(vi, queues[0], nodes, pNodes, ListLength, numLists, useNewAPI);
259 if(error) return -1;
260 }
261 else
262 {
263 error = verify_linked_lists_on_device(vi, queues[vi], num_correct, kernel_verify_lists, ListLength, numLists);
264 if(error) return -1;
265 }
266 }
267 }
268 }
269
270 clSVMFree(context, pNodes);
271
272 return 0;
273 }
274
test_svm_shared_address_space_coarse_grain_old_api(cl_device_id deviceID,cl_context context2,cl_command_queue queue,int num_elements)275 int test_svm_shared_address_space_coarse_grain_old_api(cl_device_id deviceID, cl_context context2, cl_command_queue queue, int num_elements)
276 {
277 return shared_address_space_coarse_grain(deviceID, context2, queue, num_elements, CL_FALSE);
278 }
279
test_svm_shared_address_space_coarse_grain_new_api(cl_device_id deviceID,cl_context context2,cl_command_queue queue,int num_elements)280 int test_svm_shared_address_space_coarse_grain_new_api(cl_device_id deviceID, cl_context context2, cl_command_queue queue, int num_elements)
281 {
282 return shared_address_space_coarse_grain(deviceID, context2, queue, num_elements, CL_TRUE);
283 }
284