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 "harness/testHarness.h"
17 #include "harness/typeWrappers.h"
18 #include "harness/mt19937.h"
19 #include "base.h"
20 
21 #include <string>
22 #include <vector>
23 #include <algorithm>
24 #include <sstream>
25 
26 class CStressTest : public CTest {
27 public:
CStressTest(const std::vector<std::string> & kernel)28     CStressTest(const std::vector<std::string>& kernel) : CTest(), _kernels(kernel) {
29 
30     }
31 
CStressTest(const std::string & kernel)32     CStressTest(const std::string& kernel) : CTest(), _kernels(1, kernel) {
33 
34     }
35 
ExecuteSubcase(cl_device_id deviceID,cl_context context,cl_command_queue queue,int num_elements,const std::string & src)36     int ExecuteSubcase(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements, const std::string& src) {
37         cl_int error;
38 
39         clProgramWrapper program;
40         clKernelWrapper kernel;
41 
42         const char *srcPtr = src.c_str();
43 
44         if (create_single_kernel_helper(context, &program, &kernel, 1, &srcPtr,
45                                         "testKernel"))
46         {
47             log_error("create_single_kernel_helper failed");
48             return -1;
49         }
50 
51         size_t bufferSize = num_elements * sizeof(cl_uint);
52         clMemWrapper buffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY, bufferSize, NULL, &error);
53         test_error(error, "clCreateBuffer failed");
54 
55         error = clSetKernelArg(kernel, 0, sizeof(buffer), &buffer);
56         test_error(error, "clSetKernelArg failed");
57 
58         size_t globalWorkGroupSize = num_elements;
59         size_t localWorkGroupSize = 0;
60         error = get_max_common_work_group_size(context, kernel, globalWorkGroupSize, &localWorkGroupSize);
61         test_error(error, "Unable to get common work group size");
62 
63         error = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &globalWorkGroupSize, &localWorkGroupSize, 0, NULL, NULL);
64         test_error(error, "clEnqueueNDRangeKernel failed");
65 
66         // verify results
67         std::vector<cl_uint> results(num_elements);
68 
69         error = clEnqueueReadBuffer(queue, buffer, CL_TRUE, 0, bufferSize, &results[0], 0, NULL, NULL);
70         test_error(error, "clEnqueueReadBuffer failed");
71 
72         size_t passCount = std::count(results.begin(), results.end(), 1);
73         if (passCount != results.size()) {
74             std::vector<cl_uint>::iterator iter = std::find(results.begin(), results.end(), 0);
75             log_error("Verification on device failed at index %ld\n", std::distance(results.begin(), iter));
76             log_error("%ld out of %ld failed\n", (results.size()-passCount), results.size());
77             return -1;
78         }
79 
80         return CL_SUCCESS;
81     }
82 
Execute(cl_device_id deviceID,cl_context context,cl_command_queue queue,int num_elements)83     int Execute(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) {
84         cl_int result = CL_SUCCESS;
85 
86         for (std::vector<std::string>::const_iterator it = _kernels.begin(); it != _kernels.end(); ++it) {
87             log_info("Executing subcase #%ld out of %ld\n", (it - _kernels.begin() + 1), _kernels.size());
88 
89             result |= ExecuteSubcase(deviceID, context, queue, num_elements, *it);
90         }
91 
92         return result;
93     }
94 
95 private:
96     const std::vector<std::string> _kernels;
97 };
98 
test_max_number_of_params(cl_device_id deviceID,cl_context context,cl_command_queue queue,int num_elements)99 int test_max_number_of_params(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements) {
100     cl_int error;
101 
102     size_t deviceMaxParameterSize;
103     error = clGetDeviceInfo(deviceID, CL_DEVICE_MAX_PARAMETER_SIZE, sizeof(deviceMaxParameterSize), &deviceMaxParameterSize, NULL);
104     test_error(error, "clGetDeviceInfo failed");
105 
106     size_t deviceAddressBits;
107     error = clGetDeviceInfo(deviceID, CL_DEVICE_ADDRESS_BITS, sizeof(deviceAddressBits), &deviceAddressBits, NULL);
108     test_error(error, "clGetDeviceInfo failed");
109 
110     size_t maxParams = deviceMaxParameterSize / (deviceAddressBits / 8);
111 
112     const std::string KERNEL_FUNCTION_TEMPLATE[] = {
113         common::CONFORMANCE_VERIFY_FENCE +
114         NL
115         NL "bool helperFunction(int *ptr0 ",
116             // the rest of arguments goes here
117            ") {"
118         NL "    // check first pointer only"
119         NL "    if (!isFenceValid(get_fence(ptr0)))"
120         NL "        return false;"
121         NL
122         NL "    return true;"
123         NL "}"
124         NL
125         NL "__kernel void testKernel(__global uint *results) {"
126         NL "    uint tid = get_global_id(0);"
127         NL
128         NL "    __global int * gptr;"
129         NL "    __local int * lptr;"
130         NL "    __private int * pptr;"
131         NL
132         NL "    size_t failures = 0;"
133         NL
134         NL,
135             // the function body goes here
136         NL
137         NL "    results[tid] = (failures == 0);"
138         NL "}"
139         NL
140     };
141 
142     std::ostringstream type_params;
143     std::ostringstream function_calls;
144 
145     for (size_t i = 0; i < maxParams; i++) {
146         type_params << ", int *ptr" << i+1;
147     }
148 
149     // use pseudo random generator to shuffle params
150     MTdata d = init_genrand(gRandomSeed);
151     if (!d)
152         return -1;
153 
154     std::string pointers[] = { "gptr", "lptr", "pptr" };
155 
156     size_t totalCalls = maxParams / 2;
157     for (size_t i = 0; i < totalCalls; i++) {
158         function_calls << "\tif (!helperFunction(gptr";
159 
160         for (size_t j = 0; j < maxParams; j++) {
161             function_calls << ", " << pointers[genrand_int32(d)%3];
162         }
163 
164         function_calls << ")) failures++;" << NL;
165     }
166 
167     free_mtdata(d);
168     d = NULL;
169 
170     const std::string KERNEL_FUNCTION = KERNEL_FUNCTION_TEMPLATE[0] + type_params.str() + KERNEL_FUNCTION_TEMPLATE[1] + function_calls.str() + KERNEL_FUNCTION_TEMPLATE[2];
171 
172     CStressTest test(KERNEL_FUNCTION);
173 
174     return test.Execute(deviceID, context, queue, num_elements);
175 }
176