• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "harness/mt19937.h"
18 
19 #include <vector>
20 #include <atomic>
21 
22 #if !defined(_WIN32)
23 #include <unistd.h>
24 #endif
25 
26 typedef struct
27 {
28   std::atomic<cl_uint> status;
29   cl_uint num_svm_pointers;
30   std::vector<void *> svm_pointers;
31 } CallbackData;
32 
generate_data(std::vector<cl_uchar> & data,size_t size,MTdata seed)33 void generate_data(std::vector<cl_uchar> &data, size_t size, MTdata seed)
34 {
35   cl_uint randomData = genrand_int32(seed);
36   cl_uint bitsLeft = 32;
37 
38   for( size_t i = 0; i < size; i++ )
39   {
40     if( 0 == bitsLeft)
41     {
42       randomData = genrand_int32(seed);
43       bitsLeft = 32;
44     }
45     data[i] = (cl_uchar)( randomData & 255 );
46     randomData >>= 8; randomData -= 8;
47   }
48 }
49 
50 //callback which will be passed to clEnqueueSVMFree command
callback_svm_free(cl_command_queue queue,cl_uint num_svm_pointers,void * svm_pointers[],void * user_data)51 void CL_CALLBACK callback_svm_free(cl_command_queue queue, cl_uint num_svm_pointers, void * svm_pointers[], void * user_data)
52 {
53   CallbackData *data = (CallbackData *)user_data;
54   data->num_svm_pointers = num_svm_pointers;
55   data->svm_pointers.resize(num_svm_pointers, 0);
56 
57   cl_context context;
58   if(clGetCommandQueueInfo(queue, CL_QUEUE_CONTEXT, sizeof(cl_context), &context, 0) != CL_SUCCESS)
59   {
60     log_error("clGetCommandQueueInfo failed in the callback\n");
61     return;
62   }
63 
64   for (size_t i = 0; i < num_svm_pointers; ++i)
65   {
66     data->svm_pointers[i] = svm_pointers[i];
67     clSVMFree(context, svm_pointers[i]);
68   }
69 
70   data->status.store(1, std::memory_order_release);
71 }
72 
test_svm_enqueue_api(cl_device_id deviceID,cl_context c,cl_command_queue queue,int num_elements)73 int test_svm_enqueue_api(cl_device_id deviceID, cl_context c, cl_command_queue queue, int num_elements)
74 {
75   clContextWrapper context = NULL;
76   clCommandQueueWrapper queues[MAXQ];
77   cl_uint num_devices = 0;
78   const size_t elementNum = 1024;
79   const size_t numSVMBuffers = 32;
80   cl_int error = CL_SUCCESS;
81   RandomSeed seed(0);
82 
83   error = create_cl_objects(deviceID, NULL, &context, NULL, &queues[0], &num_devices, CL_DEVICE_SVM_COARSE_GRAIN_BUFFER);
84   if(error) return TEST_FAIL;
85 
86   queue = queues[0];
87 
88   //all possible sizes of vectors and scalars
89   size_t typeSizes[] = {
90     sizeof(cl_uchar),
91     sizeof(cl_uchar2),
92     sizeof(cl_uchar3),
93     sizeof(cl_uchar4),
94     sizeof(cl_uchar8),
95     sizeof(cl_uchar16),
96     sizeof(cl_ushort),
97     sizeof(cl_ushort2),
98     sizeof(cl_ushort3),
99     sizeof(cl_ushort4),
100     sizeof(cl_ushort8),
101     sizeof(cl_ushort16),
102     sizeof(cl_uint),
103     sizeof(cl_uint2),
104     sizeof(cl_uint3),
105     sizeof(cl_uint4),
106     sizeof(cl_uint8),
107     sizeof(cl_uint16),
108     sizeof(cl_ulong),
109     sizeof(cl_ulong2),
110     sizeof(cl_ulong3),
111     sizeof(cl_ulong4),
112     sizeof(cl_ulong8),
113     sizeof(cl_ulong16),
114   };
115 
116   enum allocationTypes {
117     host,
118     svm
119   };
120 
121   struct TestType {
122     allocationTypes srcAlloc;
123     allocationTypes dstAlloc;
124     TestType(allocationTypes type1, allocationTypes type2): srcAlloc(type1), dstAlloc(type2){}
125   };
126 
127  std::vector<TestType> testTypes;
128 
129  testTypes.push_back(TestType(host, host));
130  testTypes.push_back(TestType(host, svm));
131  testTypes.push_back(TestType(svm, host));
132  testTypes.push_back(TestType(svm, svm));
133 
134   for (const auto test_case : testTypes)
135   {
136     log_info("clEnqueueSVMMemcpy case: src_alloc = %s, dst_alloc = %s\n", test_case.srcAlloc == svm ? "svm" : "host", test_case.dstAlloc == svm ? "svm" : "host");
137     for (size_t i = 0; i < ARRAY_SIZE(typeSizes); ++i)
138     {
139       //generate initial data
140       std::vector<cl_uchar> fillData0(typeSizes[i]), fillData1(typeSizes[i]);
141       generate_data(fillData0, typeSizes[i], seed);
142       generate_data(fillData1, typeSizes[i], seed);
143       size_t data_size = elementNum * typeSizes[i];
144       std::vector<cl_uchar> srcHostData(data_size, 0);
145       std::vector<cl_uchar> dstHostData(data_size, 0);
146       generate_data(srcHostData, srcHostData.size(), seed);
147       generate_data(dstHostData, dstHostData.size(), seed);
148 
149       cl_uchar *srcBuffer = (cl_uchar *)clSVMAlloc(context, CL_MEM_READ_WRITE, data_size, 0);
150       cl_uchar *dstBuffer = (cl_uchar *)clSVMAlloc(context, CL_MEM_READ_WRITE, data_size, 0);
151 
152       clEventWrapper userEvent = clCreateUserEvent(context, &error);
153       test_error(error, "clCreateUserEvent failed");
154       clEventWrapper eventMemFillList[2];
155 
156       error = clEnqueueSVMMemFill(queue, srcBuffer, &fillData0[0], typeSizes[i], data_size, 1, &userEvent, &eventMemFillList[0]);
157       test_error(error, "clEnqueueSVMMemFill failed");
158       error = clEnqueueSVMMemFill(queue, dstBuffer, &fillData1[0], typeSizes[i], data_size, 1, &userEvent, &eventMemFillList[1]);
159       test_error(error, "clEnqueueSVMMemFill failed");
160 
161       error = clSetUserEventStatus(userEvent, CL_COMPLETE);
162       test_error(error, "clSetUserEventStatus failed");
163 
164       cl_uchar * src_ptr;
165       cl_uchar * dst_ptr;
166       if (test_case.srcAlloc == host) {
167         src_ptr = srcHostData.data();
168       } else if (test_case.srcAlloc == svm) {
169         src_ptr = srcBuffer;
170       }
171       if (test_case.dstAlloc == host) {
172         dst_ptr = dstHostData.data();
173       } else if (test_case.dstAlloc == svm) {
174         dst_ptr = dstBuffer;
175       }
176       clEventWrapper eventMemcpy;
177       error = clEnqueueSVMMemcpy(queue, CL_FALSE, dst_ptr, src_ptr, data_size, 2, &eventMemFillList[0], &eventMemcpy);
178       test_error(error, "clEnqueueSVMMemcpy failed");
179 
180       //coarse grain only supported. Synchronization required using map
181       clEventWrapper eventMap[2];
182 
183       error = clEnqueueSVMMap(queue, CL_FALSE, CL_MAP_READ, srcBuffer, data_size, 1, &eventMemcpy, &eventMap[0]);
184       test_error(error, "clEnqueueSVMMap srcBuffer failed");
185 
186       error = clEnqueueSVMMap(queue, CL_FALSE, CL_MAP_READ, dstBuffer, data_size, 1, &eventMemcpy, &eventMap[1]);
187       test_error(error, "clEnqueueSVMMap dstBuffer failed");
188 
189       error = clWaitForEvents(2, &eventMap[0]);
190       test_error(error, "clWaitForEvents failed");
191 
192       //data verification
193       for (size_t j = 0; j < data_size; ++j)
194       {
195         if (dst_ptr[j] != src_ptr[j]) {
196             log_error("Invalid data at index %ld, dst_ptr %d, src_ptr %d\n", j, dst_ptr[j], src_ptr[j]);
197             return TEST_FAIL;
198         }
199       }
200       clEventWrapper eventUnmap[2];
201       error = clEnqueueSVMUnmap(queue, srcBuffer, 0, nullptr, &eventUnmap[0]);
202       test_error(error, "clEnqueueSVMUnmap srcBuffer failed");
203 
204       error = clEnqueueSVMUnmap(queue, dstBuffer, 0, nullptr, &eventUnmap[1]);
205       test_error(error, "clEnqueueSVMUnmap dstBuffer failed");
206 
207       error = clEnqueueSVMMemFill(queue, srcBuffer, &fillData1[0], typeSizes[i], data_size / 2, 0, 0, 0);
208       test_error(error, "clEnqueueSVMMemFill failed");
209 
210       error = clEnqueueSVMMemFill(queue, dstBuffer + data_size / 2, &fillData1[0], typeSizes[i], data_size / 2, 0, 0, 0);
211       test_error(error, "clEnqueueSVMMemFill failed");
212 
213       error = clEnqueueSVMMemcpy(queue, CL_FALSE, dstBuffer, srcBuffer, data_size / 2, 0, 0, 0);
214       test_error(error, "clEnqueueSVMMemcpy failed");
215 
216       error = clEnqueueSVMMemcpy(queue, CL_TRUE, dstBuffer + data_size / 2, srcBuffer + data_size / 2, data_size / 2, 0, 0, 0);
217       test_error(error, "clEnqueueSVMMemcpy failed");
218 
219       void *ptrs[] = { (void *)srcBuffer, (void *)dstBuffer };
220 
221       clEventWrapper eventFree;
222       error = clEnqueueSVMFree(queue, 2, ptrs, 0, 0, 0, 0, &eventFree);
223       test_error(error, "clEnqueueSVMFree failed");
224 
225       error = clWaitForEvents(1, &eventFree);
226       test_error(error, "clWaitForEvents failed");
227 
228       //event info verification for new SVM commands
229       cl_command_type commandType;
230       for (auto &check_event : eventMemFillList) {
231           error = clGetEventInfo(check_event, CL_EVENT_COMMAND_TYPE, sizeof(cl_command_type), &commandType, NULL);
232           test_error(error, "clGetEventInfo failed");
233           if (commandType != CL_COMMAND_SVM_MEMFILL)
234           {
235               log_error("Invalid command type returned for clEnqueueSVMMemFill\n");
236               return TEST_FAIL;
237           }
238       }
239 
240       error = clGetEventInfo(eventMemcpy, CL_EVENT_COMMAND_TYPE, sizeof(cl_command_type), &commandType, NULL);
241       test_error(error, "clGetEventInfo failed");
242       if (commandType != CL_COMMAND_SVM_MEMCPY)
243       {
244         log_error("Invalid command type returned for clEnqueueSVMMemcpy\n");
245         return TEST_FAIL;
246       }
247       for (size_t map_id = 0; map_id < ARRAY_SIZE(eventMap); map_id++) {
248           error = clGetEventInfo(eventMap[map_id], CL_EVENT_COMMAND_TYPE, sizeof(cl_command_type), &commandType, NULL);
249           test_error(error, "clGetEventInfo failed");
250           if (commandType != CL_COMMAND_SVM_MAP)
251           {
252               log_error("Invalid command type returned for clEnqueueSVMMap\n");
253               return TEST_FAIL;
254           }
255 
256           error = clGetEventInfo(eventUnmap[map_id], CL_EVENT_COMMAND_TYPE, sizeof(cl_command_type), &commandType, NULL);
257           test_error(error, "clGetEventInfo failed");
258           if (commandType != CL_COMMAND_SVM_UNMAP)
259           {
260               log_error("Invalid command type returned for clEnqueueSVMUnmap\n");
261               return TEST_FAIL;
262           }
263       }
264       error = clGetEventInfo(eventFree, CL_EVENT_COMMAND_TYPE, sizeof(cl_command_type), &commandType, NULL);
265       test_error(error, "clGetEventInfo failed");
266       if (commandType != CL_COMMAND_SVM_FREE)
267       {
268         log_error("Invalid command type returned for clEnqueueSVMFree\n");
269         return TEST_FAIL;
270       }
271     }
272   }
273   std::vector<void *> buffers(numSVMBuffers, 0);
274   for(size_t i = 0; i < numSVMBuffers; ++i) buffers[i] = clSVMAlloc(context, CL_MEM_READ_WRITE, elementNum, 0);
275 
276   //verify if callback is triggered correctly
277   CallbackData data;
278   data.status = 0;
279 
280   error = clEnqueueSVMFree(queue, buffers.size(), &buffers[0], callback_svm_free, &data, 0, 0, 0);
281   test_error(error, "clEnqueueSVMFree failed");
282 
283   error = clFinish(queue);
284   test_error(error, "clFinish failed");
285 
286   //wait for the callback
287   while(data.status.load(std::memory_order_acquire) == 0) {
288     usleep(1);
289   }
290 
291   //check if number of SVM pointers returned in the callback matches with expected
292   if (data.num_svm_pointers != buffers.size())
293   {
294     log_error("Invalid number of SVM pointers returned in the callback, expected: %ld, got: %d\n", buffers.size(), data.num_svm_pointers);
295     return TEST_FAIL;
296   }
297 
298   //check if pointers returned in callback are correct
299   for (size_t i = 0; i < buffers.size(); ++i)
300   {
301     if (data.svm_pointers[i] != buffers[i])
302     {
303       log_error("Invalid SVM pointer returned in the callback, idx: %ld\n", i);
304       return TEST_FAIL;
305     }
306   }
307 
308   return 0;
309 }
310