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