Changeset 877


Ignore:
Timestamp:
Aug 29, 2011, 7:02:47 PM (8 years ago)
Author:
sam
Message:

test: improve the benchmark code to measure a lot more half precision
number conversions.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Makefile.am

    r785 r877  
    66AUTOMAKE_OPTIONS = dist-bzip2
    77
     8bench:
     9        cd test && $(MAKE) $(AM_MAKEFLAGS) $@
     10.PHONY: bench
     11
  • trunk/src/half.cpp

    r873 r877  
    197197}
    198198
     199/* Constructor from float. Uses the non-branching version because benchmarks
     200 * indicate it is always twice as fast. The penalty of loading the lookup
     201 * tables does not seem important. */
    199202half half::makefast(float f)
    200203{
     
    203206}
    204207
     208/* Constructor from float with better precision. */
    205209half half::makeslow(float f)
    206210{
     
    209213}
    210214
     215/* Cast to float. Uses the branching version because loading the tables
     216 * for only one value is going to be cache-expensive. */
    211217half::operator float() const
    212218{
     219    /* FIXME: there is a hidden "this" in this method. Export more
     220     * code so that it can all work in registers instead. */
    213221    union { float f; uint32_t x; } u;
    214222    u.x = half_to_float_branch(bits);
     
    216224}
    217225
    218 size_t half::copy(half *dst, float const *src, size_t nelem)
     226size_t half::convert(half *dst, float const *src, size_t nelem)
    219227{
    220228    for (size_t i = 0; i < nelem; i++)
     
    228236}
    229237
    230 size_t half::copy(float *dst, half const *src, size_t nelem)
     238size_t half::convert(float *dst, half const *src, size_t nelem)
    231239{
    232240    for (size_t i = 0; i < nelem; i++)
  • trunk/src/half.h

    r874 r877  
    2626{
    2727public:
     28    /* Constructors. Always inline so that the code can work in registers
     29     * instead of calling routines with the hidden "this" parameter. */
    2830    inline half() { }
    29 
    30     inline half(float f)
    31     {
    32         *this = makefast(f);
    33     }
     31    inline half(float f) { *this = makefast(f); }
    3432
    3533    inline int is_nan() const
     
    5856
    5957    /* Array conversions */
    60     static size_t copy(half *dst, float const *src, size_t nelem);
    61     static size_t copy(float *dst, half const *src, size_t nelem);
     58    static size_t convert(half *dst, float const *src, size_t nelem);
     59    static size_t convert(float *dst, half const *src, size_t nelem);
    6260
    6361    /* Operations */
  • trunk/test/half.cpp

    r875 r877  
    3434{
    3535    CPPUNIT_TEST_SUITE(HalfTest);
     36    CPPUNIT_TEST(test_half_from_float);
     37    CPPUNIT_TEST(test_half_makeslow);
    3638    CPPUNIT_TEST(test_half_makebits);
    37     CPPUNIT_TEST(test_half_makeslow);
    38     CPPUNIT_TEST(test_half_makefast);
    3939    CPPUNIT_TEST(test_half_is_nan);
    4040    CPPUNIT_TEST(test_half_is_inf);
     
    5757    void tearDown() {}
    5858
    59     void test_half_makebits()
    60     {
    61         for (unsigned int i = 0; i < 0x10000; i++)
    62         {
    63             half a = half::makebits(i);
    64             uint16_t b = i;
     59    void test_half_from_float()
     60    {
     61        for (size_t i = 0; i < sizeof(pairs) / sizeof(*pairs); i++)
     62        {
     63            half a = (half)pairs[i].f;
     64            uint16_t b = pairs[i].x;
    6565            CPPUNIT_ASSERT_EQUAL(a.bits, b);
    6666        }
     
    7777    }
    7878
    79     void test_half_makefast()
    80     {
    81         for (size_t i = 0; i < sizeof(pairs) / sizeof(*pairs); i++)
    82         {
    83             half a = half::makefast(pairs[i].f);
    84             uint16_t b = pairs[i].x;
     79    void test_half_makebits()
     80    {
     81        for (unsigned int i = 0; i < 0x10000; i++)
     82        {
     83            half a = half::makebits(i);
     84            uint16_t b = i;
    8585            CPPUNIT_ASSERT_EQUAL(a.bits, b);
    8686        }
  • trunk/test/lol-bench.cpp

    r872 r877  
    1313#endif
    1414
     15#include <cstdio>
     16
    1517#include "core.h"
    1618#include "loldebug.h"
     
    1921using namespace lol;
    2022
     23static size_t const HALF_TABLE_SIZE = 1024 * 1024;
     24static size_t const HALF_RUNS = 100;
     25
     26static void bench_half(int mode);
     27
    2128int main(int argc, char **argv)
    2229{
    23     Timer timer;
     30    Log::Info("-----------------------------------\n");
     31    Log::Info("Half precision floats (random bits)\n");
     32    Log::Info("-----------------------------------\n");
     33    bench_half(1);
    2434
    25     float ftotal = 0.0f;
    26     for (uint32_t i = 0; i < 0xffffffffu; i += 7)
    27     {
    28         union { float f; uint32_t x; } u;
    29         u.x = i;
    30 
    31         float h = (float)half::makefast(u.f);
    32         ftotal += h;
    33     }
    34     Log::Info("time for makeslow: %f (hash %f)\n", timer.GetMs(), ftotal);
    35 
    36     uint16_t total = 0;
    37     for (uint32_t i = 0; i < 0xffffffffu; i += 7)
    38     {
    39         union { float f; uint32_t x; } u;
    40         u.x = i;
    41 
    42         half h = half::makeslow(u.f);
    43         total ^= h.bits;
    44     }
    45     Log::Info("time for makeslow: %f (hash %04x)\n", timer.GetMs(), total);
    46 
    47     for (uint32_t i = 0; i < 0xffffffffu; i += 7)
    48     {
    49         union { float f; uint32_t x; } u;
    50         u.x = i;
    51 
    52         half h = half::makefast(u.f);
    53         total ^= h.bits;
    54     }
    55     Log::Info("time for makefast: %f (hash %04x)\n", timer.GetMs(), total);
     35    Log::Info("---------------------------------\n");
     36    Log::Info("Half precision floats [-2.0, 2.0]\n");
     37    Log::Info("---------------------------------\n");
     38    bench_half(2);
    5639
    5740    return EXIT_SUCCESS;
    5841}
    5942
     43static void bench_half(int mode)
     44{
     45    float result[8] = { 0.0f };
     46    Timer timer;
     47
     48    /* Set up tables */
     49    float *pf = new float[HALF_TABLE_SIZE];
     50    half *ph = new half[HALF_TABLE_SIZE];
     51
     52    switch (mode)
     53    {
     54    case 1:
     55        for (size_t i = 0; i < HALF_TABLE_SIZE; i++)
     56            ph[i] = half::makebits(rand());
     57        break;
     58    case 2:
     59        for (size_t i = 0; i < HALF_TABLE_SIZE; i++)
     60            ph[i] = RandF(-2.0f, 2.0f);
     61        break;
     62    }
     63
     64    for (size_t run = 0; run < HALF_RUNS; run++)
     65    {
     66        /* Convert half to float (array) */
     67        timer.GetMs();
     68        half::convert(pf, ph, HALF_TABLE_SIZE);
     69        result[1] += timer.GetMs();
     70
     71        /* Convert half to float (fast) */
     72        timer.GetMs();
     73        for (size_t i = 0; i < HALF_TABLE_SIZE; i++)
     74            pf[i] = (float)ph[i];
     75        result[0] += timer.GetMs();
     76
     77        /* Convert float to half (array) */
     78        timer.GetMs();
     79        half::convert(ph, pf, HALF_TABLE_SIZE);
     80        result[4] += timer.GetMs();
     81
     82        /* Convert float to half (fast) */
     83        timer.GetMs();
     84        for (size_t i = 0; i < HALF_TABLE_SIZE; i++)
     85            ph[i] = (half)pf[i];
     86        result[2] += timer.GetMs();
     87
     88        /* Convert float to half (slow) */
     89        timer.GetMs();
     90        for (size_t i = 0; i < HALF_TABLE_SIZE; i++)
     91            ph[i] = half::makeslow(pf[i]);
     92        result[3] += timer.GetMs();
     93
     94        /* Change sign of every half */
     95        timer.GetMs();
     96        for (size_t i = 0; i < HALF_TABLE_SIZE; i++)
     97            ph[i] = -ph[i];
     98        result[5] += timer.GetMs();
     99
     100        /* Add a half to every float */
     101        timer.GetMs();
     102        for (size_t i = 0; i < HALF_TABLE_SIZE; i++)
     103            pf[i] += ph[i];
     104        result[6] += timer.GetMs();
     105
     106        /* Add a float to every half */
     107        timer.GetMs();
     108        for (size_t i = 0; i < HALF_TABLE_SIZE; i++)
     109            ph[i] += pf[i];
     110        result[7] += timer.GetMs();
     111    }
     112
     113    delete[]pf;
     114    delete[]ph;
     115
     116    for (size_t i = 0; i < sizeof(result) / sizeof(*result); i++)
     117        result[i] *= 1000000.0f / (HALF_TABLE_SIZE * HALF_RUNS);
     118
     119    Log::Info("                         ns/elem\n");
     120    Log::Info("float = half            %7.3f\n", result[0]);
     121    Log::Info("float[] = half[]        %7.3f\n", result[1]);
     122    Log::Info("half = float            %7.3f\n", result[2]);
     123    Log::Info("half = makeslow(float)  %7.3f\n", result[3]);
     124    Log::Info("half[] = float[]        %7.3f\n", result[4]);
     125    Log::Info("half = -half            %7.3f\n", result[5]);
     126    Log::Info("float += half           %7.3f\n", result[6]);
     127    Log::Info("half += float           %7.3f\n", result[7]);
     128}
     129
Note: See TracChangeset for help on using the changeset viewer.