Плавающее и двойное тестирование производительности на Beagle Bone Black

Я выполняю некоторую обработку изображений на своем Beaglebone Black и заинтересован в повышении производительности при использовании поплавков против двойников в моем алгоритме.

Я попытался разработать простой тест для этого:

main.c

#define MAX_TEST 10
#define MAX_ITER 1E7
#define DELTA 1E-8 

void float_test()
{
    float n = 0.0;
    for (int i=0; i<MAX_ITER; i++)
    {
        n += DELTA;
        n /= 3.0;
    }
}


void double_test()
{
    double n = 0.0;
    for (int i=0; i<MAX_ITER; i++)
    {
        n += DELTA;
        n /= 3.0;
    }
}


int main()
{
    for (int i=0; i<MAX_TEST; i++)
    {
        double_test();
        float_test();
    }

    return 0;
}

работал как:

gcc -Wall -pg main.c  -std=c99
./a.out
gprof a.out gmon.out -q > profile.txt

профиль.txt:

granularity: each sample hit covers 4 byte(s) for 0.03% of 35.31 seconds

index % time    self  children    called     name
                                                 <spontaneous>
[1]    100.0    0.00   35.31                 main [1]
               18.74    0.00      10/10          float_test [2]
               16.57    0.00      10/10          double_test [3]
-----------------------------------------------
               18.74    0.00      10/10          main [1]
[2]     53.1   18.74    0.00      10         float_test [2]
-----------------------------------------------
               16.57    0.00      10/10          main [1]
[3]     46.9   16.57    0.00      10         double_test [3]
-----------------------------------------------

Я не уверен, оптимизирует ли компилятор часть моего кода или я делаю достаточно арифметических действий, чтобы это имело значение. Я нахожу немного странным, что double_test() на самом деле занимает меньше времени, чем float_test().

Я попытался изменить порядок вызова функций, и результаты остались прежними. Может ли кто-нибудь объяснить мне это?


person Robert Lee Murrer III    schedule 07.08.2014    source источник
comment
Если вы не уверены, что компилятор оптимизирует что-то, почему бы вам не заставить вашу программу получать важные входные данные (или, по крайней мере, считывать их из изменчивых мест) и печатать вычисленный вывод? PS: да, полуприличный оптимизирующий компилятор должен удалить все вычисления PS2: почему вы вообще измеряете время, затрачиваемое программой, которая не скомпилирована с оптимизацией? Тогда не должно быть никакого смысла в относительном времени, затраченном double и float.   -  person Pascal Cuoq    schedule 07.08.2014
comment
C позволяет вычислять FP с большей точностью, чем это необходимо. См. настройку FLT_EVAL_METHOD.   -  person chux - Reinstate Monica    schedule 07.08.2014


Ответы (1)


На моей машине (x86_64), глядя на сгенерированный код рядом:

double_test:                                  .. float_test:
  xorpd  %xmm0,%xmm0  // double n             --   xorps  %xmm0,%xmm0      // float n
  xor    %eax,%eax    // int i                ==   xor    %eax,%eax
loop:                                         .. loop:
                                              ++   unpcklps %xmm0,%xmm0    // Extend float n to...
                                              ++   cvtps2pd %xmm0,%xmm0    // ...double n
  add    $0x1,%eax     // ++i                 ==   add    $0x1,%eax
  addsd  %xmm2,%xmm0   // double n += DELTA   ==   addsd  %xmm2,%xmm0
  cvtsi2sd %eax,%xmm3  // (double)i           ==   cvtsi2sd %eax,%xmm3
                                              ++   unpcklpd %xmm0,%xmm0    // Reduce double n to...
                                              ++   cvtpd2ps %xmm0,%xmm0    // ...float n
  divsd  %xmm5,%xmm0   // double n /= 3.0     --   divss  %xmm4,%xmm0      // float n / 3.0
  ucomisd %xmm3,%xmm1  // (double)i cmp 1E7   ==   ucomisd %xmm3,%xmm1
  ja      ...loop...   // if (double)i < 1E7  ==   ja      ...loop...

показаны четыре дополнительные инструкции для изменения вверх до double и обратно до float, чтобы добавить DELTA.

DELTA — это 1E-8, что неявно равно double. Итак, добавив, что сделано double. Конечно, 3.0 также неявно double, но я предполагаю, что компилятор замечает, что в этом случае нет эффективной разницы между double и single.

Определение DELTAF как 1E-8f избавляет от изменения вверх и вниз от double для добавления.

person Community    schedule 07.08.2014