Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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 <jfonseca@vmware.com>
  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("test_module", LLVMGetGlobalContext());
  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.    gallivm_free_ir(gallivm);
  223.  
  224.    success = TRUE;
  225.    for(i = 0; i < n && success; ++i) {
  226.       unsigned src_stride = src_type.length*src_type.width/8;
  227.       unsigned dst_stride = dst_type.length*dst_type.width/8;
  228.       PIPE_ALIGN_VAR(LP_MIN_VECTOR_ALIGN) uint8_t src[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
  229.       PIPE_ALIGN_VAR(LP_MIN_VECTOR_ALIGN) uint8_t dst[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
  230.       double fref[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
  231.       uint8_t ref[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
  232.       int64_t start_counter = 0;
  233.       int64_t end_counter = 0;
  234.  
  235.       for(j = 0; j < num_srcs; ++j) {
  236.          random_vec(src_type, src + j*src_stride);
  237.          read_vec(src_type, src + j*src_stride, fref + j*src_type.length);
  238.       }
  239.  
  240.       for(j = 0; j < num_dsts; ++j) {
  241.          write_vec(dst_type, ref + j*dst_stride, fref + j*dst_type.length);
  242.       }
  243.  
  244.       start_counter = rdtsc();
  245.       conv_test_ptr(src, dst);
  246.       end_counter = rdtsc();
  247.  
  248.       cycles[i] = end_counter - start_counter;
  249.  
  250.       for(j = 0; j < num_dsts; ++j) {
  251.          if(!compare_vec_with_eps(dst_type, dst + j*dst_stride, ref + j*dst_stride, eps))
  252.             success = FALSE;
  253.       }
  254.  
  255.       if (!success || verbose >= 3) {
  256.          if(verbose < 1)
  257.             dump_conv_types(stderr, src_type, dst_type);
  258.          if (success) {
  259.             fprintf(stderr, "PASS\n");
  260.          }
  261.          else {
  262.             fprintf(stderr, "MISMATCH\n");
  263.          }
  264.  
  265.          for(j = 0; j < num_srcs; ++j) {
  266.             fprintf(stderr, "  Src%u: ", j);
  267.             dump_vec(stderr, src_type, src + j*src_stride);
  268.             fprintf(stderr, "\n");
  269.          }
  270.  
  271. #if 1
  272.          fprintf(stderr, "  Ref: ");
  273.          for(j = 0; j < src_type.length*num_srcs; ++j)
  274.             fprintf(stderr, " %f", fref[j]);
  275.          fprintf(stderr, "\n");
  276. #endif
  277.  
  278.          for(j = 0; j < num_dsts; ++j) {
  279.             fprintf(stderr, "  Dst%u: ", j);
  280.             dump_vec(stderr, dst_type, dst + j*dst_stride);
  281.             fprintf(stderr, "\n");
  282.  
  283.             fprintf(stderr, "  Ref%u: ", j);
  284.             dump_vec(stderr, dst_type, ref + j*dst_stride);
  285.             fprintf(stderr, "\n");
  286.          }
  287.       }
  288.    }
  289.  
  290.    /*
  291.     * Unfortunately the output of cycle counter is not very reliable as it comes
  292.     * -- sometimes we get outliers (due IRQs perhaps?) which are
  293.     * better removed to avoid random or biased data.
  294.     */
  295.    {
  296.       double sum = 0.0, sum2 = 0.0;
  297.       double avg, std;
  298.       unsigned m;
  299.  
  300.       for(i = 0; i < n; ++i) {
  301.          sum += cycles[i];
  302.          sum2 += cycles[i]*cycles[i];
  303.       }
  304.  
  305.       avg = sum/n;
  306.       std = sqrtf((sum2 - n*avg*avg)/n);
  307.  
  308.       m = 0;
  309.       sum = 0.0;
  310.       for(i = 0; i < n; ++i) {
  311.          if(fabs(cycles[i] - avg) <= 4.0*std) {
  312.             sum += cycles[i];
  313.             ++m;
  314.          }
  315.       }
  316.  
  317.       cycles_avg = sum/m;
  318.  
  319.    }
  320.  
  321.    if(fp)
  322.       write_tsv_row(fp, src_type, dst_type, cycles_avg, success);
  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. }
  454.