// // Copyright (c) 2017 The Khronos Group Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "testBase.h" #include "action_classes.h" extern const char *IGetStatusString(cl_int status); #define PRINT_OPS 0 int test_waitlist(cl_device_id device, cl_context context, cl_command_queue queue, Action *actionToTest, bool multiple) { NDRangeKernelAction actions[2]; clEventWrapper events[3]; cl_int status[3]; cl_int error; if (multiple) log_info("\tExecuting reference event 0, then reference event 1 with " "reference event 0 in its waitlist, then test event 2 with " "reference events 0 and 1 in its waitlist.\n"); else log_info("\tExecuting reference event 0, then test event 2 with " "reference event 0 in its waitlist.\n"); // Set up the first base action to wait against error = actions[0].Setup(device, context, queue); test_error(error, "Unable to setup base event to wait against"); if (multiple) { // Set up a second event to wait against error = actions[1].Setup(device, context, queue); test_error(error, "Unable to setup second base event to wait against"); } // Now set up the actual action to test error = actionToTest->Setup(device, context, queue); test_error(error, "Unable to set up test event"); // Execute all events now if (PRINT_OPS) log_info("\tExecuting action 0...\n"); error = actions[0].Execute(queue, 0, NULL, &events[0]); test_error(error, "Unable to execute first event"); if (multiple) { if (PRINT_OPS) log_info("\tExecuting action 1...\n"); error = actions[1].Execute(queue, 1, &events[0], &events[1]); test_error(error, "Unable to execute second event"); } // Sanity check if (multiple) { if (PRINT_OPS) log_info("\tChecking status of action 1...\n"); error = clGetEventInfo(events[1], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(status[1]), &status[1], NULL); test_error(error, "Unable to get event status"); } if (PRINT_OPS) log_info("\tChecking status of action 0...\n"); error = clGetEventInfo(events[0], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(status[0]), &status[0], NULL); test_error(error, "Unable to get event status"); log_info("\t\tEvent status after starting reference events: reference " "event 0: %s, reference event 1: %s, test event 2: %s.\n", IGetStatusString(status[0]), (multiple ? IGetStatusString(status[1]) : "N/A"), "N/A"); if ((status[0] == CL_COMPLETE) || (multiple && status[1] == CL_COMPLETE)) { log_info("WARNING: Reference event(s) already completed before we " "could execute test event! Possible that the reference event " "blocked (implicitly passing)\n"); return 0; } if (PRINT_OPS) log_info("\tExecuting action to test...\n"); error = actionToTest->Execute(queue, (multiple) ? 2 : 1, &events[0], &events[2]); test_error(error, "Unable to execute test event"); // Hopefully, the first event is still running if (PRINT_OPS) log_info("\tChecking status of action to test 2...\n"); error = clGetEventInfo(events[2], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(status[2]), &status[2], NULL); test_error(error, "Unable to get event status"); if (multiple) { if (PRINT_OPS) log_info("\tChecking status of action 1...\n"); error = clGetEventInfo(events[1], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(status[1]), &status[1], NULL); test_error(error, "Unable to get event status"); } if (PRINT_OPS) log_info("\tChecking status of action 0...\n"); error = clGetEventInfo(events[0], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(status[0]), &status[0], NULL); test_error(error, "Unable to get event status"); log_info("\t\tEvent status after starting test event: reference event 0: " "%s, reference event 1: %s, test event 2: %s.\n", IGetStatusString(status[0]), (multiple ? IGetStatusString(status[1]) : "N/A"), IGetStatusString(status[2])); if (multiple) { if (status[0] == CL_COMPLETE && status[1] == CL_COMPLETE) { log_info("WARNING: Both events completed, so unable to test " "further (implicitly passing).\n"); clFinish(queue); return 0; } if (status[1] == CL_COMPLETE && status[0] != CL_COMPLETE) { log_error( "ERROR: Test failed because the second wait event is complete " "and the first is not.(status: 0: %s and 1: %s)\n", IGetStatusString(status[0]), IGetStatusString(status[1])); clFinish(queue); return -1; } } else { if (status[0] == CL_COMPLETE) { log_info("WARNING: Reference event completed, so unable to test " "further (implicitly passing).\n"); clFinish(queue); return 0; } if (status[0] != CL_RUNNING && status[0] != CL_QUEUED && status[0] != CL_SUBMITTED) { log_error( "ERROR: Test failed because first wait event is not currently " "running, queued, or submitted! (status: 0: %s)\n", IGetStatusString(status[0])); clFinish(queue); return -1; } } if (status[2] != CL_QUEUED && status[2] != CL_SUBMITTED) { log_error("ERROR: Test event is not waiting to run! (status: 2: %s)\n", IGetStatusString(status[2])); clFinish(queue); return -1; } // Now wait for the first reference event if (PRINT_OPS) log_info("\tWaiting for action 1 to finish...\n"); error = clWaitForEvents(1, &events[0]); test_error(error, "Unable to wait for reference event"); // Grab statuses again if (PRINT_OPS) log_info("\tChecking status of action to test 2...\n"); error = clGetEventInfo(events[2], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(status[2]), &status[2], NULL); test_error(error, "Unable to get event status"); if (multiple) { if (PRINT_OPS) log_info("\tChecking status of action 1...\n"); error = clGetEventInfo(events[1], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(status[1]), &status[1], NULL); test_error(error, "Unable to get event status"); } if (PRINT_OPS) log_info("\tChecking status of action 0...\n"); error = clGetEventInfo(events[0], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(status[0]), &status[0], NULL); test_error(error, "Unable to get event status"); log_info("\t\tEvent status after waiting for reference event 0: reference " "event 0: %s, reference event 1: %s, test event 2: %s.\n", IGetStatusString(status[0]), (multiple ? IGetStatusString(status[1]) : "N/A"), IGetStatusString(status[2])); // Sanity if (status[0] != CL_COMPLETE) { log_error("ERROR: Waited for first event but it's not complete " "(status: 0: %s)\n", IGetStatusString(status[0])); clFinish(queue); return -1; } // If we're multiple, and the second event isn't complete, then our test // event should still be queued if (multiple && status[1] != CL_COMPLETE) { if (status[1] == CL_RUNNING && status[2] == CL_RUNNING) { log_error("ERROR: Test event and second event are both running.\n"); clFinish(queue); return -1; } if (status[2] != CL_QUEUED && status[2] != CL_SUBMITTED) { log_error("ERROR: Test event did not wait for second event before " "starting! (status of ref: 1: %s, of test: 2: %s)\n", IGetStatusString(status[1]), IGetStatusString(status[2])); clFinish(queue); return -1; } // Now wait for second event to complete, too if (PRINT_OPS) log_info("\tWaiting for action 1 to finish...\n"); error = clWaitForEvents(1, &events[1]); test_error(error, "Unable to wait for second reference event"); // Grab statuses again if (PRINT_OPS) log_info("\tChecking status of action to test 2...\n"); error = clGetEventInfo(events[2], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(status[2]), &status[2], NULL); test_error(error, "Unable to get event status"); if (multiple) { if (PRINT_OPS) log_info("\tChecking status of action 1...\n"); error = clGetEventInfo(events[1], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(status[1]), &status[1], NULL); test_error(error, "Unable to get event status"); } if (PRINT_OPS) log_info("\tChecking status of action 0...\n"); error = clGetEventInfo(events[0], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(status[0]), &status[0], NULL); test_error(error, "Unable to get event status"); log_info( "\t\tEvent status after waiting for reference event 1: reference " "event 0: %s, reference event 1: %s, test event 2: %s.\n", IGetStatusString(status[0]), (multiple ? IGetStatusString(status[1]) : "N/A"), IGetStatusString(status[2])); // Sanity if (status[1] != CL_COMPLETE) { log_error("ERROR: Waited for second reference event but it didn't " "complete (status: 1: %s)\n", IGetStatusString(status[1])); clFinish(queue); return -1; } } // At this point, the test event SHOULD be running, but if it completed, we // consider it a pass if (status[2] == CL_COMPLETE) { log_info("WARNING: Test event already completed. Assumed valid.\n"); clFinish(queue); return 0; } if (status[2] != CL_RUNNING && status[2] != CL_SUBMITTED && status[2] != CL_QUEUED) { log_error("ERROR: Second event did not start running after reference " "event(s) completed! (status: 2: %s)\n", IGetStatusString(status[2])); clFinish(queue); return -1; } // Wait for the test event, then return if (PRINT_OPS) log_info("\tWaiting for action 2 to test to finish...\n"); error = clWaitForEvents(1, &events[2]); test_error(error, "Unable to wait for test event"); error |= clGetEventInfo(events[2], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(status[2]), &status[2], NULL); test_error(error, "Unable to get event status"); log_info("\t\tEvent status after waiting for test event: reference event " "0: %s, reference event 1: %s, test event 2: %s.\n", IGetStatusString(status[0]), (multiple ? IGetStatusString(status[1]) : "N/A"), IGetStatusString(status[2])); // Sanity if (status[2] != CL_COMPLETE) { log_error("ERROR: Test event didn't complete (status: 2: %s)\n", IGetStatusString(status[2])); clFinish(queue); return -1; } clFinish(queue); return 0; } #define TEST_ACTION(name) \ { \ name##Action action; \ log_info("-- Testing " #name " (waiting on 1 event)...\n"); \ if ((error = test_waitlist(deviceID, context, queue, &action, false)) \ != CL_SUCCESS) \ retVal++; \ clFinish(queue); \ } \ if (error \ == CL_SUCCESS) /* Only run multiples test if single test passed */ \ { \ name##Action action; \ log_info("-- Testing " #name " (waiting on 2 events)...\n"); \ if ((error = test_waitlist(deviceID, context, queue, &action, true)) \ != CL_SUCCESS) \ retVal++; \ clFinish(queue); \ } int test_waitlists(cl_device_id deviceID, cl_context context, cl_command_queue oldQueue, int num_elements) { cl_int error; int retVal = 0; cl_command_queue_properties props = CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE; if (!checkDeviceForQueueSupport(deviceID, props)) { log_info("WARNING: Device does not support out-of-order exec mode; " "skipping test.\n"); return 0; } clCommandQueueWrapper queue = clCreateCommandQueue(context, deviceID, props, &error); test_error(error, "Unable to create out-of-order queue"); log_info("\n"); TEST_ACTION(NDRangeKernel) TEST_ACTION(ReadBuffer) TEST_ACTION(WriteBuffer) TEST_ACTION(MapBuffer) TEST_ACTION(UnmapBuffer) if (checkForImageSupport(deviceID) == CL_IMAGE_FORMAT_NOT_SUPPORTED) { log_info("\nNote: device does not support images. Skipping remainder " "of waitlist tests...\n"); } else { TEST_ACTION(ReadImage2D) TEST_ACTION(WriteImage2D) TEST_ACTION(CopyImage2Dto2D) TEST_ACTION(Copy2DImageToBuffer) TEST_ACTION(CopyBufferTo2DImage) TEST_ACTION(MapImage) if (checkFor3DImageSupport(deviceID) == CL_IMAGE_FORMAT_NOT_SUPPORTED) log_info("Device does not support 3D images. Skipping remainder of " "waitlist tests...\n"); else { TEST_ACTION(ReadImage3D) TEST_ACTION(WriteImage3D) TEST_ACTION(CopyImage2Dto3D) TEST_ACTION(CopyImage3Dto2D) TEST_ACTION(CopyImage3Dto3D) TEST_ACTION(Copy3DImageToBuffer) TEST_ACTION(CopyBufferTo3DImage) } } return retVal; }