xref: /aosp_15_r20/external/OpenCL-CTS/test_conformance/events/test_callbacks.cpp (revision 6467f958c7de8070b317fc65bcb0f6472e388d82)
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 "testBase.h"
17 #include "action_classes.h"
18 #include "harness/conversions.h"
19 #include "harness/ThreadPool.h"
20 
21 #if !defined(_MSC_VER)
22 #include <unistd.h>
23 #endif // !_MSC_VER
24 
25 extern const char *IGetStatusString(cl_int status);
26 
27 #define PRINT_OPS 0
28 
29 // Yes, this is somewhat nasty, in that we're relying on the CPU (the real CPU,
30 // not the OpenCL device) to be atomic w.r.t. boolean values. Although if it
31 // isn't, we'll just miss the check on this bool until the next time around, so
32 // it's not that big of a deal. Ideally, we'd be using a semaphore with a
33 // trywait on it, but then that introduces the fun issue of what to do on Win32,
34 // etc. This way is far more portable, and worst case of failure is a slightly
35 // longer test run.
36 static bool sCallbackTriggered = false;
37 
38 
39 #define EVENT_CALLBACK_TYPE_TOTAL 3
40 static bool sCallbackTriggered_flag[EVENT_CALLBACK_TYPE_TOTAL] = { false, false,
41                                                                    false };
42 cl_int event_callback_types[EVENT_CALLBACK_TYPE_TOTAL] = { CL_SUBMITTED,
43                                                            CL_RUNNING,
44                                                            CL_COMPLETE };
45 
46 // Our callback function
47 /*void CL_CALLBACK single_event_callback_function( cl_event event, cl_int
48 commandStatus, void * userData )
49 {
50      int i=*static_cast<int *>(userData);
51     log_info( "\tEvent callback  %d   triggered\n",  i);
52     sCallbackTriggered_flag [ i ] = true;
53 }*/
54 
55 /*   use struct as call back para */
56 typedef struct
57 {
58     cl_int event_type;
59     int index;
60 } CALL_BACK_USER_DATA;
61 
single_event_callback_function_flags(cl_event event,cl_int commandStatus,void * userData)62 void CL_CALLBACK single_event_callback_function_flags(cl_event event,
63                                                       cl_int commandStatus,
64                                                       void *userData)
65 {
66     // int i=*static_cast<int *>(userData);
67     CALL_BACK_USER_DATA *pdata = static_cast<CALL_BACK_USER_DATA *>(userData);
68 
69     log_info("\tEvent callback  %d  of type %d triggered\n", pdata->index,
70              pdata->event_type);
71     sCallbackTriggered_flag[pdata->index] = true;
72 }
73 
test_callback_event_single(cl_device_id device,cl_context context,cl_command_queue queue,Action * actionToTest)74 int test_callback_event_single(cl_device_id device, cl_context context,
75                                cl_command_queue queue, Action *actionToTest)
76 {
77     // Note: we don't use the waiting feature here. We just want to verify that
78     // we get a callback called when the given event finishes
79 
80     cl_int error = actionToTest->Setup(device, context, queue);
81     test_error(error, "Unable to set up test action");
82 
83     // Set up a user event, which we use as a gate for the second event
84     clEventWrapper gateEvent = clCreateUserEvent(context, &error);
85     test_error(error, "Unable to set up user gate event");
86 
87     // Set up the execution of the action with its actual event
88     clEventWrapper actualEvent;
89     error = actionToTest->Execute(queue, 1, &gateEvent, &actualEvent);
90     test_error(error, "Unable to set up action execution");
91 
92     // Set up the callback on the actual event
93 
94     /*  use struct as call back para */
95     CALL_BACK_USER_DATA user_data[EVENT_CALLBACK_TYPE_TOTAL];
96     for (int i = 0; i < EVENT_CALLBACK_TYPE_TOTAL; i++)
97     {
98         user_data[i].event_type = event_callback_types[i];
99         user_data[i].index = i;
100         error = clSetEventCallback(actualEvent, event_callback_types[i],
101                                    single_event_callback_function_flags,
102                                    user_data + i);
103     }
104 
105     // Now release the user event, which will allow our actual action to run
106     error = clSetUserEventStatus(gateEvent, CL_COMPLETE);
107     test_error(error, "Unable to trigger gate event");
108 
109     // Now we wait for completion. Note that we can actually wait on the event
110     // itself, at least at first
111     error = clWaitForEvents(1, &actualEvent);
112     test_error(error, "Unable to wait for actual test event");
113 
114     // Note: we can check our callback now, and it MIGHT have been triggered,
115     // but that's not guaranteed
116     if (sCallbackTriggered)
117     {
118         // We're all good, so return success
119         return 0;
120     }
121 
122     // The callback has not yet been called, but that doesn't mean it won't be.
123     // So wait for it
124     log_info("\tWaiting for callback...");
125     fflush(stdout);
126     for (int i = 0; i < 10 * 10; i++)
127     {
128         usleep(100000); // 1/10th second
129 
130         int cc = 0;
131         for (int k = 0; k < EVENT_CALLBACK_TYPE_TOTAL; k++)
132             if (sCallbackTriggered_flag[k])
133             {
134                 cc++;
135             }
136 
137         if (cc == EVENT_CALLBACK_TYPE_TOTAL)
138         {
139             log_info("\n");
140             return 0;
141         }
142         log_info(".");
143         fflush(stdout);
144     }
145 
146     // If we got here, we never got the callback
147     log_error("\nCallback not called within 10 seconds! (assuming failure)\n");
148     return -1;
149 }
150 
151 #define TEST_ACTION(name)                                                      \
152     {                                                                          \
153         name##Action action;                                                   \
154         log_info("-- Testing " #name "...\n");                                 \
155         if ((error = test_callback_event_single(deviceID, context, queue,      \
156                                                 &action))                      \
157             != CL_SUCCESS)                                                     \
158             retVal++;                                                          \
159         clFinish(queue);                                                       \
160     }
161 
test_callbacks(cl_device_id deviceID,cl_context context,cl_command_queue queue,int num_elements)162 int test_callbacks(cl_device_id deviceID, cl_context context,
163                    cl_command_queue queue, int num_elements)
164 {
165     cl_int error;
166     int retVal = 0;
167 
168     log_info("\n");
169 
170     TEST_ACTION(NDRangeKernel)
171 
172     TEST_ACTION(ReadBuffer)
173     TEST_ACTION(WriteBuffer)
174     TEST_ACTION(MapBuffer)
175     TEST_ACTION(UnmapBuffer)
176 
177     if (checkForImageSupport(deviceID) == CL_IMAGE_FORMAT_NOT_SUPPORTED)
178     {
179         log_info("\nNote: device does not support images. Skipping remainder "
180                  "of callback tests...\n");
181     }
182     else
183     {
184         TEST_ACTION(ReadImage2D)
185         TEST_ACTION(WriteImage2D)
186         TEST_ACTION(CopyImage2Dto2D)
187         TEST_ACTION(Copy2DImageToBuffer)
188         TEST_ACTION(CopyBufferTo2DImage)
189         TEST_ACTION(MapImage)
190 
191         if (checkFor3DImageSupport(deviceID) == CL_IMAGE_FORMAT_NOT_SUPPORTED)
192             log_info("\nNote: device does not support 3D images. Skipping "
193                      "remainder of waitlist tests...\n");
194         else
195         {
196             TEST_ACTION(ReadImage3D)
197             TEST_ACTION(WriteImage3D)
198             TEST_ACTION(CopyImage2Dto3D)
199             TEST_ACTION(CopyImage3Dto2D)
200             TEST_ACTION(CopyImage3Dto3D)
201             TEST_ACTION(Copy3DImageToBuffer)
202             TEST_ACTION(CopyBufferTo3DImage)
203         }
204     }
205 
206     return retVal;
207 }
208 
209 #define SIMUTANEOUS_ACTION_TOTAL 18
210 static bool sSimultaneousFlags[54]; // for 18 actions with 3 callback status
211 static volatile int sSimultaneousCount;
212 
213 Action *actions[19] = { 0 };
214 
215 // Callback for the simultaneous tests
simultaneous_event_callback_function(cl_event event,cl_int commandStatus,void * userData)216 void CL_CALLBACK simultaneous_event_callback_function(cl_event event,
217                                                       cl_int commandStatus,
218                                                       void *userData)
219 {
220     int eventIndex = (int)(size_t)userData;
221     int actionIndex = eventIndex / EVENT_CALLBACK_TYPE_TOTAL;
222     int statusIndex = eventIndex % EVENT_CALLBACK_TYPE_TOTAL;
223     log_info("\tEvent callback triggered for action %s callback type %s \n",
224              actions[actionIndex]->GetName(), IGetStatusString(statusIndex));
225     sSimultaneousFlags[actionIndex] = true;
226     ThreadPool_AtomicAdd(&sSimultaneousCount, 1);
227 }
228 
test_callbacks_simultaneous(cl_device_id deviceID,cl_context context,cl_command_queue queue,int num_elements)229 int test_callbacks_simultaneous(cl_device_id deviceID, cl_context context,
230                                 cl_command_queue queue, int num_elements)
231 {
232     cl_int error;
233 
234     // Unlike the singles test, in this one, we run a bunch of events all at
235     // once, to verify that the callbacks do get called once-and-only-once for
236     // each event, even if the run out of order or are dependent on each other
237 
238     // First, the list of actions to run
239     int actionCount = 0, index = 0;
240 
241     actions[index++] = new NDRangeKernelAction();
242     actions[index++] = new ReadBufferAction();
243     actions[index++] = new WriteBufferAction();
244     actions[index++] = new MapBufferAction();
245     actions[index++] = new UnmapBufferAction();
246 
247     if (checkForImageSupport(deviceID) != CL_IMAGE_FORMAT_NOT_SUPPORTED)
248     {
249         actions[index++] = new ReadImage2DAction();
250         actions[index++] = new WriteImage2DAction();
251         actions[index++] = new CopyImage2Dto2DAction();
252         actions[index++] = new Copy2DImageToBufferAction();
253         actions[index++] = new CopyBufferTo2DImageAction();
254         actions[index++] = new MapImageAction();
255 
256         if (checkFor3DImageSupport(deviceID) != CL_IMAGE_FORMAT_NOT_SUPPORTED)
257         {
258             actions[index++] = new ReadImage3DAction();
259             actions[index++] = new WriteImage3DAction();
260             actions[index++] = new CopyImage2Dto3DAction();
261             actions[index++] = new CopyImage3Dto2DAction();
262             actions[index++] = new CopyImage3Dto3DAction();
263             actions[index++] = new Copy3DImageToBufferAction();
264             actions[index++] = new CopyBufferTo3DImageAction();
265         }
266     }
267     actionCount = index;
268     actions[index++] = NULL;
269 
270     // Now set them all up
271     log_info("\tSetting up test events...\n");
272     for (index = 0; actions[index] != NULL; index++)
273     {
274         error = actions[index]->Setup(deviceID, context, queue);
275         test_error(error, "Unable to set up test action");
276         sSimultaneousFlags[index] = false;
277     }
278     sSimultaneousCount = 0;
279 
280     // Set up the user event to start them all
281     clEventWrapper gateEvent = clCreateUserEvent(context, &error);
282     test_error(error, "Unable to set up user gate event");
283 
284     // Start executing, all tied to the gate event
285     // clEventWrapper actionEvents[ 18 ];// current actionCount is 18
286     clEventWrapper *actionEvents = new clEventWrapper[actionCount];
287     if (actionEvents == NULL)
288     {
289         log_error(" memory error in test_callbacks_simultaneous  \n");
290         for (size_t i = 0; i < (sizeof(actions) / sizeof(actions[0])); ++i)
291             if (actions[i]) delete actions[i];
292         return -1;
293     }
294 
295     RandomSeed seed(gRandomSeed);
296     for (index = 0; actions[index] != NULL; index++)
297     {
298         // Randomly choose to wait on the gate, or wait on the previous event
299         cl_event *eventPtr = &gateEvent;
300         if ((index > 0) && (random_in_range(0, 255, seed) & 1))
301             eventPtr = &actionEvents[index - 1];
302 
303         error =
304             actions[index]->Execute(queue, 1, eventPtr, &actionEvents[index]);
305         test_error(error, "Unable to execute test action");
306 
307 
308         for (int k = 0; k < EVENT_CALLBACK_TYPE_TOTAL; k++)
309         {
310             error = clSetEventCallback(
311                 actionEvents[index], event_callback_types[k],
312                 simultaneous_event_callback_function,
313                 (void *)(size_t)(index * EVENT_CALLBACK_TYPE_TOTAL + k));
314             test_error(error, "Unable to set event callback function");
315         }
316     }
317 
318     int total_callbacks = actionCount * EVENT_CALLBACK_TYPE_TOTAL;
319 
320     // Now release the user event, which will allow our actual action to run
321     error = clSetUserEventStatus(gateEvent, CL_COMPLETE);
322     test_error(error, "Unable to trigger gate event");
323 
324     // Wait on the actual action events now
325     log_info("\tWaiting for test completions...\n");
326     error = clWaitForEvents(actionCount, &actionEvents[0]);
327     test_error(error, "Unable to wait for actual test events");
328 
329     // Note: we can check our callback now, and it MIGHT have been triggered,
330     // but that's not guaranteed
331     int last_count = 0;
332     if (((last_count = sSimultaneousCount)) == total_callbacks)
333     {
334         // We're all good, so return success
335         log_info("\t%d of %d callbacks received\n", sSimultaneousCount,
336                  total_callbacks);
337 
338         if (actionEvents) delete[] actionEvents;
339         for (size_t i = 0; i < (sizeof(actions) / sizeof(actions[0])); ++i)
340             if (actions[i]) delete actions[i];
341         return 0;
342     }
343 
344     // We haven't gotten (all) of the callbacks, so wait for them
345     log_info("\tWe've only received %d of the %d callbacks we expected; "
346              "waiting for more...\n",
347              last_count, total_callbacks);
348 
349     for (int i = 0; i < 10 * 10; i++)
350     {
351         usleep(100000); // 1/10th second
352         if (((last_count = sSimultaneousCount)) == total_callbacks)
353         {
354             // All of the callbacks were executed
355             if (actionEvents) delete[] actionEvents;
356             for (size_t i = 0; i < (sizeof(actions) / sizeof(actions[0])); ++i)
357                 if (actions[i]) delete actions[i];
358             return 0;
359         }
360     }
361 
362     // If we got here, some of the callbacks did not occur in time
363     log_error("\nError: We only ever received %d of our %d callbacks!\n",
364               last_count, total_callbacks);
365     log_error("Events that did not receive callbacks:\n");
366     for (index = 0; actions[index] != NULL; index++)
367     {
368         if (!sSimultaneousFlags[index])
369             log_error("\t%s\n", actions[index]->GetName());
370     }
371 
372     if (actionEvents) delete[] actionEvents;
373     return -1;
374 }
375