1 /* ************************************************************************
2 * Copyright 2013 Advanced Micro Devices, 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
17
18 /*
19 * test generator and cache infrastructure
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #ifdef __APPLE__
27 #include <OpenCL/cl.h>
28 #else
29 #include <CL/cl.h>
30 #endif
31
32 #include <kerngen.h>
33 #include <kern_cache.h>
34
35 enum {
36 NR_TEST_PATTERNS = 5,
37 KERNELS_PER_PATTERN = 10,
38 KCACHE_SIZE_LIMIT = 1048576
39 };
40
41 const char *strcpyImpl =
42 "char\n"
43 "*strcpy(char *dst, char *src)\n"
44 "{\n"
45 " do {\n"
46 " *dst++ = *src++;\n"
47 " } while (*(dst - 1) != 0);\n"
48 "}";
49
50 static int
testGenFunc(struct KgenContext * ctx)51 testGenFunc(struct KgenContext *ctx)
52 {
53 kgenDeclareFunction(ctx, "char\n"
54 "*strcpy(char *dst, char *src)\n");
55 kgenBeginFuncBody(ctx);
56 kgenAddStmt(ctx, "char *ret = dst;\n\n");
57 kgenBeginBranch(ctx, "do");
58 kgenAddStmt(ctx, "*dst = *src;\n"
59 "src++;\n"
60 "dst++;\n");
61 kgenEndBranch(ctx, "while (*(dst - 1) != 0)");
62 kgenAddBlankLine(ctx);
63 kgenAddStmt(ctx, "return ret;\n");
64
65 return kgenEndFuncBody(ctx);
66 }
67
68 static int
kernExtraCmp(const void * extra,const void * extraKey)69 kernExtraCmp(const void *extra, const void *extraKey)
70 {
71 unsigned long u1 = *(unsigned long*)extra;
72 unsigned long u2 = *(unsigned long*)extraKey;
73
74 return !(u1 == u2);
75 }
76
77
78 static int
testGen(void)79 testGen(void)
80 {
81 char buf[4096];
82 char name[64];
83 int r;
84 struct KgenContext *ctx;
85 size_t s;
86
87 ctx = createKgenContext(buf, sizeof(buf), true);
88 if (ctx == NULL) {
89 printf("Context creation failed\n");
90 printf("FAIL\n\n");
91 return -1;
92 }
93
94 printf("Test normal kernel generation\n");
95 if (!testGenFunc(ctx)) {
96 printf("Generated code:\n\n");
97 printf("%s", buf);
98 printf("\n\nPASS\n\n");
99 }
100 else {
101 printf("FAIL\n\n");
102 }
103
104 printf("Test function name extracting from the generated code\n");
105 r = kgenGetLastFuncName(name, sizeof(name), ctx);
106 if (r) {
107 printf("FAIL\n");
108 }
109 else {
110 if (strcmp((const char*)name, "strcpy")) {
111 printf("Extracted names is %s must be strcpy\n", name);
112 printf("FAIL\n\n");
113 r = -1;
114 }
115 else {
116 printf("PASS\n\n");
117 }
118 }
119
120 destroyKgenContext(ctx);
121
122 printf("Test source size calculating without actual source "
123 "adding to any buffer\n");
124 ctx = createKgenContext(NULL, 0, true);
125 r = kgenAddStmt(ctx, strcpyImpl);
126 if (!r) {
127 s = kgenSourceSize(ctx);
128 if (s != strlen(strcpyImpl)) {
129 r = -1;
130 }
131 }
132 if (r) {
133 printf("FAIL\n\n");
134 }
135 else {
136 printf("PASS\n\n");
137 }
138 destroyKgenContext(ctx);
139
140 ctx = createKgenContext(buf, 5, true);
141
142 if (!r) {
143 printf("Test generation with insufficient buffer\n");
144 if (testGenFunc(ctx)) {
145 printf("PASS\n");
146 }
147 else {
148 printf("FAIL\n");
149 r = -1;
150 }
151 }
152
153 return r;
154 }
155
156 // test case for kache error functionality
157 static int
errorCacheTestCase(const char * msg,struct KernelCache * kcache,solver_id_t sid,SubproblemDim * dims,unsigned int nrDims,cl_context context,cl_device_id device,unsigned long extra,Kernel * kern)158 errorCacheTestCase(
159 const char *msg,
160 struct KernelCache *kcache,
161 solver_id_t sid,
162 SubproblemDim *dims,
163 unsigned int nrDims,
164 cl_context context,
165 cl_device_id device,
166 unsigned long extra,
167 Kernel *kern)
168 {
169 KernelKey key;
170 Kernel* krn1;
171 int r;
172 bool fail;
173
174 key.device = device;
175 key.context = context;
176 key.nrDims = nrDims;
177 memset(key.subdims, 0, sizeof(key.subdims));
178 r = nrDims;
179 if (nrDims > MAX_SUBDIMS)
180 r = MAX_SUBDIMS;
181 memcpy(key.subdims, dims, sizeof(SubproblemDim) * r);
182
183 printf("%s", msg);
184 if (kern == NULL) {
185 krn1 = findKernel(kcache, sid, &key, &extra);
186 fail = (krn1 != NULL);
187 }
188 else {
189 r = addKernelToCache(kcache, sid, kern, &key, kernExtraCmp);
190 fail = (r == 0);
191 }
192
193 if (fail) {
194 printf("FAIL\n");
195 r = -1;
196 }
197 else {
198 printf("PASS\n");
199 r = 0;
200 }
201
202 return r;
203 }
204
205 static int
testCache(cl_context context,cl_device_id device)206 testCache(cl_context context, cl_device_id device)
207 {
208 int r = 0;
209 int i, j;
210 unsigned int k;
211 const solver_id_t wrongSID = 15;
212 struct KernelCache *kcache;
213 KernelKey key;
214 Kernel *kern[NR_TEST_PATTERNS][KERNELS_PER_PATTERN], *krn1;
215 SubproblemDim dims[NR_TEST_PATTERNS][KERNELS_PER_PATTERN][MAX_SUBDIMS];
216 unsigned int nrDims[NR_TEST_PATTERNS] = {1, 3, 2, 2, 1};
217 unsigned long extra = 7, extra1;
218
219 printf("Testing inserting and normal searching of kernels\n");
220 kcache = createKernelCache(10, KCACHE_SIZE_LIMIT);
221
222 key.device = device;
223 key.context = context;
224
225 for (i = 0; (i < NR_TEST_PATTERNS) && !r; i++) {
226 for (j = 0; (j < KERNELS_PER_PATTERN) && !r; j++) {
227 for (k = 0; k < nrDims[i]; k++) {
228 dims[i][j][k].x = random() % 1000;
229 if (k == 2) {
230 dims[i][j][k].y = SUBDIM_UNUSED;
231 dims[i][j][k].itemX = SUBDIM_UNUSED;
232 }
233 else {
234 dims[i][j][k].y = random() % 1000;
235 dims[i][j][k].itemX = random() % 1000;
236 }
237 dims[i][j][k].bwidth = random() % 1000;
238 dims[i][j][k].itemY = random() % 1000;
239 }
240
241 kern[i][j] = allocKernel();
242 kern[i][j]->extra = &extra;
243 kern[i][j]->extraSize = sizeof(extra);
244 key.nrDims = nrDims[i];
245 memset(key.subdims, 0, sizeof(key.subdims));
246 memcpy(key.subdims, dims[i][j], sizeof(SubproblemDim) * key.nrDims);
247 r = addKernelToCache(kcache, i, kern[i][j], &key, kernExtraCmp);
248 }
249 }
250
251 if (r) {
252 printf("Error at addition to the cache, i = %d, j = %d\n", i, j);
253 printf("FAIL\n");
254 }
255 else {
256 // Now try to find each cached kernel
257 extra1 = extra;
258 for (i = 0; (i < NR_TEST_PATTERNS) && !r; i++) {
259 for (j = 0; j < KERNELS_PER_PATTERN; j++) {
260 key.nrDims = nrDims[i];
261 memset(key.subdims, 0, sizeof(key.subdims));
262 memcpy(key.subdims, dims[i][j], sizeof(SubproblemDim) * key.nrDims);
263 krn1 = findKernel(kcache, i, &key, &extra1);
264 if (krn1 != kern[i][j]) {
265 r = -1;
266 break;
267 }
268 }
269 }
270 if (r) {
271 printf("First error occurred at pattern %d, kernel %d: ", i, j);
272 if (krn1 == NULL) {
273 printf("the kernel is not found\n");
274 }
275 else {
276 printf("the kernel mismatch\n");
277 }
278 }
279 else {
280 printf("PASS\n");
281 }
282 }
283
284 // cases for search error functionality
285 dims[0][0][0].x = 1001;
286
287 if (!r) {
288 r = errorCacheTestCase("Try to search a kernel not being in "
289 "the cache\n",
290 kcache, 0, dims[0][0],
291 nrDims[0], context, device, extra, NULL);
292 }
293
294 if (!r) {
295 r = errorCacheTestCase("Try To search a kernel with a wrong extra "
296 "information\n", kcache, 0, dims[0][1],
297 nrDims[0], context, device, extra - 2, NULL);
298 }
299
300 if (!r) {
301 r = errorCacheTestCase("Try to search a kernel with a solver "
302 "ID\n", kcache, wrongSID,
303 dims[0][1], nrDims[0], context, device,
304 extra, NULL);
305 }
306
307 if (!r) {
308 r = errorCacheTestCase("Try to search a kernel with a wrong number "
309 "of subproblem dimensions\n",
310 kcache, 0, dims[0][1], 500, context, device,
311 extra, NULL);
312 }
313 if (!r) {
314 r = errorCacheTestCase("Try to search a kernel with bad OpenCL context\n",
315 kcache, 0, dims[0][1], 500, (cl_context)-1, device,
316 extra, NULL);
317 }
318 if (!r) {
319 r = errorCacheTestCase("Try to search a kernel with bad OpenCL device\n",
320 kcache, 0, dims[0][1], 500, context,
321 (cl_device_id)-1, extra, NULL);
322 }
323
324 // error test cases for inserting to cache
325 krn1 = allocKernel();
326 krn1->extra = &extra;
327 krn1->extraSize = sizeof(extra);
328
329 if (!r) {
330 r = errorCacheTestCase("Try to insert a kernel with a wrong solver "
331 "ID\n", kcache, wrongSID,
332 dims[0][0], nrDims[0], context, device,
333 extra, krn1);
334 }
335
336 if (!r) {
337 r = errorCacheTestCase("Try to insert a kernel with a wrong number "
338 "of subproblem dimensions\n",
339 kcache, 0, dims[0][0],
340 500, context, device, extra, krn1);
341 }
342
343 return r;
344 }
345
346
347 int
main(void)348 main(void)
349 {
350 cl_int err;
351 cl_platform_id platform;
352 cl_device_id device;
353 cl_context_properties props[] = { CL_CONTEXT_PLATFORM, 0, 0 };
354 cl_context context;
355
356 err = clGetPlatformIDs(1, &platform, NULL);
357 if (err != CL_SUCCESS) {
358 fprintf(stderr, "clGetPlatformIDs() failed with %d\n", err);
359 return 1;
360 }
361 err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL);
362 if (err != CL_SUCCESS) {
363 fprintf(stderr, "clGetDeviceIDs() failed with %d\n", err);
364 return 1;
365 }
366 props[1] = (cl_context_properties)platform;
367 context = clCreateContext(props, 1, &device, NULL, NULL, &err);
368 if (err != CL_SUCCESS) {
369 fprintf(stderr, "clCreateContext() failed with %d\n", err);
370 return 1;
371 }
372
373 printf("Launch tests for kernel generators\n");
374 printf("-----------------------------------------\n");
375 if (!testGen()) {
376 printf("-----------------------------------------\n\n");
377 printf("Launch tests for kernel cache\n");
378 printf("-----------------------------------------\n");
379 testCache(context, device);
380 }
381
382 clReleaseContext(context);
383 return 0;
384 }
385
386