1 //
2 // Copyright (c) 2017-2020 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 
18 #if !defined(_WIN32)
19 #include <unistd.h>
20 #endif
21 
22 #include <atomic>
23 #include <string>
24 
25 namespace {
26 
27 const char *sample_async_kernel[] = {
28     "__kernel void sample_test(__global float *src, __global int *dst)\n"
29     "{\n"
30     "    size_t tid = get_global_id(0);\n"
31     "\n"
32     "    dst[tid] = (int)src[tid];\n"
33     "\n"
34     "}\n"
35 };
36 
37 const char *sample_async_kernel_error[] = {
38     "__kernel void sample_test(__global float *src, __global int *dst)\n"
39     "{\n"
40     "    size_t tid = get_global_id(0);\n"
41     "\n"
42     "    dst[tid] = badcodehere;\n"
43     "\n"
44     "}\n"
45 };
46 
47 // Data passed to a program completion callback
48 struct TestData
49 {
50     cl_device_id device;
51     cl_build_status expectedStatus;
52 };
53 
54 std::atomic<int> callbackResult;
55 
56 }
57 
test_notify_build_complete(cl_program program,void * userData)58 void CL_CALLBACK test_notify_build_complete(cl_program program, void *userData)
59 {
60     TestData *data = reinterpret_cast<TestData *>(userData);
61 
62     // Check user data is valid
63     if (data == nullptr)
64     {
65         log_error("ERROR: User data passed to callback was not valid!\n");
66         callbackResult = -1;
67         return;
68     }
69 
70     // Get program build status
71     cl_build_status status;
72     cl_int err =
73         clGetProgramBuildInfo(program, data->device, CL_PROGRAM_BUILD_STATUS,
74                               sizeof(cl_build_status), &status, NULL);
75     if (err != CL_SUCCESS)
76     {
77         log_info("ERROR: failed to get build status from callback\n");
78         callbackResult = -1;
79         return;
80     }
81 
82     log_info("Program completion callback received build status %d\n", status);
83 
84     // Check program build status matches expectation
85     if (status != data->expectedStatus)
86     {
87         log_info("ERROR: build status %d != expected status %d\n", status,
88                  data->expectedStatus);
89         callbackResult = -1;
90     }
91     else
92     {
93         callbackResult = 1;
94     }
95 }
96 
test_async_build(cl_device_id deviceID,cl_context context,cl_command_queue queue,int num_elements)97 int test_async_build(cl_device_id deviceID, cl_context context,
98                      cl_command_queue queue, int num_elements)
99 {
100     cl_int error;
101 
102     struct TestDef
103     {
104         const char **source;
105         cl_build_status expectedStatus;
106     };
107 
108     TestDef testDefs[] = { { sample_async_kernel, CL_BUILD_SUCCESS },
109                            { sample_async_kernel_error, CL_BUILD_ERROR } };
110     for (TestDef &testDef : testDefs)
111     {
112         log_info("\nTesting program that should produce status %d\n",
113                  testDef.expectedStatus);
114 
115         // Create the program
116         clProgramWrapper program;
117         error = create_single_kernel_helper_create_program(context, &program, 1,
118                                                            testDef.source);
119         test_error(error, "Unable to create program from source");
120 
121         // Start an asynchronous build, registering the completion callback
122         TestData testData = { deviceID, testDef.expectedStatus };
123         callbackResult = 0;
124         error = clBuildProgram(program, 1, &deviceID, NULL,
125                                test_notify_build_complete, (void *)&testData);
126         // Allow implementations to return synchronous build failures.
127         // They still need to call the callback.
128         if (!(error == CL_BUILD_PROGRAM_FAILURE
129               && testDef.expectedStatus == CL_BUILD_ERROR))
130             test_error(error, "Unable to start build");
131 
132         // Wait for callback to fire
133         int timeout = 20;
134         while (callbackResult == 0)
135         {
136             if (timeout < 0)
137             {
138                 log_error("Timeout while waiting for callback to fire.\n\n");
139                 return -1;
140             }
141 
142             log_info(" -- still waiting for callback...\n");
143             sleep(1);
144             timeout--;
145         }
146 
147         // Check the callback result
148         if (callbackResult == 1)
149         {
150             log_error("Test passed.\n\n");
151         }
152         else
153         {
154             log_error("Async build callback indicated test failure.\n\n");
155             return -1;
156         }
157     }
158 
159     return 0;
160 }
161