Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/**************************************************************************
2
 *
3
 * Copyright 2009 VMware, Inc.
4
 * All Rights Reserved.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sub license, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 *
14
 * The above copyright notice and this permission notice (including the
15
 * next paragraph) shall be included in all copies or substantial portions
16
 * of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21
 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 *
26
 **************************************************************************/
27
 
28
 
29
/**
30
 * @file
31
 * Unit tests for type conversion.
32
 *
33
 * @author Jose Fonseca 
34
 */
35
 
36
 
37
#include "util/u_pointer.h"
38
#include "gallivm/lp_bld_init.h"
39
#include "gallivm/lp_bld_type.h"
40
#include "gallivm/lp_bld_const.h"
41
#include "gallivm/lp_bld_conv.h"
42
#include "gallivm/lp_bld_debug.h"
43
#include "lp_test.h"
44
 
45
 
46
typedef void (*conv_test_ptr_t)(const void *src, const void *dst);
47
 
48
 
49
void
50
write_tsv_header(FILE *fp)
51
{
52
   fprintf(fp,
53
           "result\t"
54
           "cycles_per_channel\t"
55
           "src_type\t"
56
           "dst_type\n");
57
 
58
   fflush(fp);
59
}
60
 
61
 
62
static void
63
write_tsv_row(FILE *fp,
64
              struct lp_type src_type,
65
              struct lp_type dst_type,
66
              double cycles,
67
              boolean success)
68
{
69
   fprintf(fp, "%s\t", success ? "pass" : "fail");
70
 
71
   fprintf(fp, "%.1f\t", cycles / MAX2(src_type.length, dst_type.length));
72
 
73
   dump_type(fp, src_type);
74
   fprintf(fp, "\t");
75
 
76
   dump_type(fp, dst_type);
77
   fprintf(fp, "\n");
78
 
79
   fflush(fp);
80
}
81
 
82
 
83
static void
84
dump_conv_types(FILE *fp,
85
               struct lp_type src_type,
86
               struct lp_type dst_type)
87
{
88
   fprintf(fp, "src_type=");
89
   dump_type(fp, src_type);
90
 
91
   fprintf(fp, " dst_type=");
92
   dump_type(fp, dst_type);
93
 
94
   fprintf(fp, " ...\n");
95
   fflush(fp);
96
}
97
 
98
 
99
static LLVMValueRef
100
add_conv_test(struct gallivm_state *gallivm,
101
              struct lp_type src_type, unsigned num_srcs,
102
              struct lp_type dst_type, unsigned num_dsts)
103
{
104
   LLVMModuleRef module = gallivm->module;
105
   LLVMContextRef context = gallivm->context;
106
   LLVMBuilderRef builder = gallivm->builder;
107
   LLVMTypeRef args[2];
108
   LLVMValueRef func;
109
   LLVMValueRef src_ptr;
110
   LLVMValueRef dst_ptr;
111
   LLVMBasicBlockRef block;
112
   LLVMValueRef src[LP_MAX_VECTOR_LENGTH];
113
   LLVMValueRef dst[LP_MAX_VECTOR_LENGTH];
114
   unsigned i;
115
 
116
   args[0] = LLVMPointerType(lp_build_vec_type(gallivm, src_type), 0);
117
   args[1] = LLVMPointerType(lp_build_vec_type(gallivm, dst_type), 0);
118
 
119
   func = LLVMAddFunction(module, "test",
120
                          LLVMFunctionType(LLVMVoidTypeInContext(context),
121
                                           args, 2, 0));
122
   LLVMSetFunctionCallConv(func, LLVMCCallConv);
123
   src_ptr = LLVMGetParam(func, 0);
124
   dst_ptr = LLVMGetParam(func, 1);
125
 
126
   block = LLVMAppendBasicBlockInContext(context, func, "entry");
127
   LLVMPositionBuilderAtEnd(builder, block);
128
 
129
   for(i = 0; i < num_srcs; ++i) {
130
      LLVMValueRef index = LLVMConstInt(LLVMInt32TypeInContext(context), i, 0);
131
      LLVMValueRef ptr = LLVMBuildGEP(builder, src_ptr, &index, 1, "");
132
      src[i] = LLVMBuildLoad(builder, ptr, "");
133
   }
134
 
135
   lp_build_conv(gallivm, src_type, dst_type, src, num_srcs, dst, num_dsts);
136
 
137
   for(i = 0; i < num_dsts; ++i) {
138
      LLVMValueRef index = LLVMConstInt(LLVMInt32TypeInContext(context), i, 0);
139
      LLVMValueRef ptr = LLVMBuildGEP(builder, dst_ptr, &index, 1, "");
140
      LLVMBuildStore(builder, dst[i], ptr);
141
   }
142
 
143
   LLVMBuildRetVoid(builder);;
144
 
145
   gallivm_verify_function(gallivm, func);
146
 
147
   return func;
148
}
149
 
150
 
151
PIPE_ALIGN_STACK
152
static boolean
153
test_one(unsigned verbose,
154
         FILE *fp,
155
         struct lp_type src_type,
156
         struct lp_type dst_type)
157
{
158
   struct gallivm_state *gallivm;
159
   LLVMValueRef func = NULL;
160
   conv_test_ptr_t conv_test_ptr;
161
   boolean success;
162
   const unsigned n = LP_TEST_NUM_SAMPLES;
163
   int64_t cycles[LP_TEST_NUM_SAMPLES];
164
   double cycles_avg = 0.0;
165
   unsigned num_srcs;
166
   unsigned num_dsts;
167
   double eps;
168
   unsigned i, j;
169
 
170
   if ((src_type.width >= dst_type.width && src_type.length > dst_type.length) ||
171
       (src_type.width <= dst_type.width && src_type.length < dst_type.length)) {
172
      return TRUE;
173
   }
174
 
175
   /* Known failures
176
    * - fixed point 32 -> float 32
177
    * - float 32 -> signed normalised integer 32
178
    */
179
   if ((src_type.floating && !dst_type.floating && dst_type.sign && dst_type.norm && src_type.width == dst_type.width) ||
180
       (!src_type.floating && dst_type.floating && src_type.fixed && src_type.width == dst_type.width)) {
181
      return TRUE;
182
   }
183
 
184
   /* Known failures
185
    * - fixed point 32 -> float 32
186
    * - float 32 -> signed normalised integer 32
187
    */
188
   if ((src_type.floating && !dst_type.floating && dst_type.sign && dst_type.norm && src_type.width == dst_type.width) ||
189
       (!src_type.floating && dst_type.floating && src_type.fixed && src_type.width == dst_type.width)) {
190
      return TRUE;
191
   }
192
 
193
   if(verbose >= 1)
194
      dump_conv_types(stderr, src_type, dst_type);
195
 
196
   if (src_type.length > dst_type.length) {
197
      num_srcs = 1;
198
      num_dsts = src_type.length/dst_type.length;
199
   }
200
   else if (src_type.length < dst_type.length) {
201
      num_dsts = 1;
202
      num_srcs = dst_type.length/src_type.length;
203
   }
204
   else  {
205
      num_dsts = 1;
206
      num_srcs = 1;
207
   }
208
 
209
   /* We must not loose or gain channels. Only precision */
210
   assert(src_type.length * num_srcs == dst_type.length * num_dsts);
211
 
212
   eps = MAX2(lp_const_eps(src_type), lp_const_eps(dst_type));
213
 
214
   gallivm = gallivm_create();
215
 
216
   func = add_conv_test(gallivm, src_type, num_srcs, dst_type, num_dsts);
217
 
218
   gallivm_compile_module(gallivm);
219
 
220
   conv_test_ptr = (conv_test_ptr_t)gallivm_jit_function(gallivm, func);
221
 
222
   success = TRUE;
223
   for(i = 0; i < n && success; ++i) {
224
      unsigned src_stride = src_type.length*src_type.width/8;
225
      unsigned dst_stride = dst_type.length*dst_type.width/8;
226
      PIPE_ALIGN_VAR(LP_MIN_VECTOR_ALIGN) uint8_t src[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
227
      PIPE_ALIGN_VAR(LP_MIN_VECTOR_ALIGN) uint8_t dst[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
228
      double fref[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
229
      uint8_t ref[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
230
      int64_t start_counter = 0;
231
      int64_t end_counter = 0;
232
 
233
      for(j = 0; j < num_srcs; ++j) {
234
         random_vec(src_type, src + j*src_stride);
235
         read_vec(src_type, src + j*src_stride, fref + j*src_type.length);
236
      }
237
 
238
      for(j = 0; j < num_dsts; ++j) {
239
         write_vec(dst_type, ref + j*dst_stride, fref + j*dst_type.length);
240
      }
241
 
242
      start_counter = rdtsc();
243
      conv_test_ptr(src, dst);
244
      end_counter = rdtsc();
245
 
246
      cycles[i] = end_counter - start_counter;
247
 
248
      for(j = 0; j < num_dsts; ++j) {
249
         if(!compare_vec_with_eps(dst_type, dst + j*dst_stride, ref + j*dst_stride, eps))
250
            success = FALSE;
251
      }
252
 
253
      if (!success || verbose >= 3) {
254
         if(verbose < 1)
255
            dump_conv_types(stderr, src_type, dst_type);
256
         if (success) {
257
            fprintf(stderr, "PASS\n");
258
         }
259
         else {
260
            fprintf(stderr, "MISMATCH\n");
261
         }
262
 
263
         for(j = 0; j < num_srcs; ++j) {
264
            fprintf(stderr, "  Src%u: ", j);
265
            dump_vec(stderr, src_type, src + j*src_stride);
266
            fprintf(stderr, "\n");
267
         }
268
 
269
#if 1
270
         fprintf(stderr, "  Ref: ");
271
         for(j = 0; j < src_type.length*num_srcs; ++j)
272
            fprintf(stderr, " %f", fref[j]);
273
         fprintf(stderr, "\n");
274
#endif
275
 
276
         for(j = 0; j < num_dsts; ++j) {
277
            fprintf(stderr, "  Dst%u: ", j);
278
            dump_vec(stderr, dst_type, dst + j*dst_stride);
279
            fprintf(stderr, "\n");
280
 
281
            fprintf(stderr, "  Ref%u: ", j);
282
            dump_vec(stderr, dst_type, ref + j*dst_stride);
283
            fprintf(stderr, "\n");
284
         }
285
      }
286
   }
287
 
288
   /*
289
    * Unfortunately the output of cycle counter is not very reliable as it comes
290
    * -- sometimes we get outliers (due IRQs perhaps?) which are
291
    * better removed to avoid random or biased data.
292
    */
293
   {
294
      double sum = 0.0, sum2 = 0.0;
295
      double avg, std;
296
      unsigned m;
297
 
298
      for(i = 0; i < n; ++i) {
299
         sum += cycles[i];
300
         sum2 += cycles[i]*cycles[i];
301
      }
302
 
303
      avg = sum/n;
304
      std = sqrtf((sum2 - n*avg*avg)/n);
305
 
306
      m = 0;
307
      sum = 0.0;
308
      for(i = 0; i < n; ++i) {
309
         if(fabs(cycles[i] - avg) <= 4.0*std) {
310
            sum += cycles[i];
311
            ++m;
312
         }
313
      }
314
 
315
      cycles_avg = sum/m;
316
 
317
   }
318
 
319
   if(fp)
320
      write_tsv_row(fp, src_type, dst_type, cycles_avg, success);
321
 
322
   gallivm_free_function(gallivm, func, conv_test_ptr);
323
 
324
   gallivm_destroy(gallivm);
325
 
326
   return success;
327
}
328
 
329
 
330
const struct lp_type conv_types[] = {
331
   /* float, fixed,  sign,  norm, width, len */
332
 
333
   /* Float */
334
   {   TRUE, FALSE,  TRUE,  TRUE,    32,   4 },
335
   {   TRUE, FALSE,  TRUE, FALSE,    32,   4 },
336
   {   TRUE, FALSE, FALSE,  TRUE,    32,   4 },
337
   {   TRUE, FALSE, FALSE, FALSE,    32,   4 },
338
 
339
   {   TRUE, FALSE,  TRUE,  TRUE,    32,   8 },
340
   {   TRUE, FALSE,  TRUE, FALSE,    32,   8 },
341
   {   TRUE, FALSE, FALSE,  TRUE,    32,   8 },
342
   {   TRUE, FALSE, FALSE, FALSE,    32,   8 },
343
 
344
   /* Fixed */
345
   {  FALSE,  TRUE,  TRUE,  TRUE,    32,   4 },
346
   {  FALSE,  TRUE,  TRUE, FALSE,    32,   4 },
347
   {  FALSE,  TRUE, FALSE,  TRUE,    32,   4 },
348
   {  FALSE,  TRUE, FALSE, FALSE,    32,   4 },
349
 
350
   {  FALSE,  TRUE,  TRUE,  TRUE,    32,   8 },
351
   {  FALSE,  TRUE,  TRUE, FALSE,    32,   8 },
352
   {  FALSE,  TRUE, FALSE,  TRUE,    32,   8 },
353
   {  FALSE,  TRUE, FALSE, FALSE,    32,   8 },
354
 
355
   /* Integer */
356
   {  FALSE, FALSE,  TRUE,  TRUE,    32,   4 },
357
   {  FALSE, FALSE,  TRUE, FALSE,    32,   4 },
358
   {  FALSE, FALSE, FALSE,  TRUE,    32,   4 },
359
   {  FALSE, FALSE, FALSE, FALSE,    32,   4 },
360
 
361
   {  FALSE, FALSE,  TRUE,  TRUE,    32,   8 },
362
   {  FALSE, FALSE,  TRUE, FALSE,    32,   8 },
363
   {  FALSE, FALSE, FALSE,  TRUE,    32,   8 },
364
   {  FALSE, FALSE, FALSE, FALSE,    32,   8 },
365
 
366
   {  FALSE, FALSE,  TRUE,  TRUE,    16,   8 },
367
   {  FALSE, FALSE,  TRUE, FALSE,    16,   8 },
368
   {  FALSE, FALSE, FALSE,  TRUE,    16,   8 },
369
   {  FALSE, FALSE, FALSE, FALSE,    16,   8 },
370
 
371
   {  FALSE, FALSE,  TRUE,  TRUE,     8,  16 },
372
   {  FALSE, FALSE,  TRUE, FALSE,     8,  16 },
373
   {  FALSE, FALSE, FALSE,  TRUE,     8,  16 },
374
   {  FALSE, FALSE, FALSE, FALSE,     8,  16 },
375
 
376
   {  FALSE, FALSE,  TRUE,  TRUE,     8,   4 },
377
   {  FALSE, FALSE,  TRUE, FALSE,     8,   4 },
378
   {  FALSE, FALSE, FALSE,  TRUE,     8,   4 },
379
   {  FALSE, FALSE, FALSE, FALSE,     8,   4 },
380
 
381
   {  FALSE, FALSE,  FALSE,  TRUE,    8,   8 },
382
};
383
 
384
 
385
const unsigned num_types = sizeof(conv_types)/sizeof(conv_types[0]);
386
 
387
 
388
boolean
389
test_all(unsigned verbose, FILE *fp)
390
{
391
   const struct lp_type *src_type;
392
   const struct lp_type *dst_type;
393
   boolean success = TRUE;
394
   int error_count = 0;
395
 
396
   for(src_type = conv_types; src_type < &conv_types[num_types]; ++src_type) {
397
      for(dst_type = conv_types; dst_type < &conv_types[num_types]; ++dst_type) {
398
 
399
         if(src_type == dst_type)
400
            continue;
401
 
402
         if(!test_one(verbose, fp, *src_type, *dst_type)){
403
            success = FALSE;
404
            ++error_count;
405
         }
406
      }
407
   }
408
 
409
   fprintf(stderr, "%d failures\n", error_count);
410
 
411
   return success;
412
}
413
 
414
 
415
boolean
416
test_some(unsigned verbose, FILE *fp,
417
          unsigned long n)
418
{
419
   const struct lp_type *src_type;
420
   const struct lp_type *dst_type;
421
   unsigned long i;
422
   boolean success = TRUE;
423
 
424
   for(i = 0; i < n; ++i) {
425
      src_type = &conv_types[rand() % num_types];
426
 
427
      do {
428
         dst_type = &conv_types[rand() % num_types];
429
      } while (src_type == dst_type || src_type->norm != dst_type->norm);
430
 
431
      if(!test_one(verbose, fp, *src_type, *dst_type))
432
        success = FALSE;
433
   }
434
 
435
   return success;
436
}
437
 
438
 
439
boolean
440
test_single(unsigned verbose, FILE *fp)
441
{
442
   /*    float, fixed,  sign,  norm, width, len */
443
   struct lp_type f32x4_type =
444
      {   TRUE, FALSE,  TRUE,  TRUE,    32,   4 };
445
   struct lp_type ub8x4_type =
446
      {  FALSE, FALSE, FALSE,  TRUE,     8,  16 };
447
 
448
   boolean success;
449
 
450
   success = test_one(verbose, fp, f32x4_type, ub8x4_type);
451
 
452
   return success;
453
}