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