Оптимизация БИХ-фильтра - PullRequest
3 голосов
/ 22 марта 2012

Быстрый вопрос, связанный с коэффициентами фильтра БИХ.Вот очень типичная реализация двухпроцессорного IIR-процессора прямой формы II, который я нашел в сети.

// b0, b1, b2, a1, a2 are filter coefficients
// m1, m2 are the memory locations
// dn is the de-denormal coeff (=1.0e-20f) 

void processBiquad(const float* in, float* out, unsigned length)
{
    for(unsigned i = 0; i < length; ++i)
    {
        register float w = in[i] - a1*m1 - a2*m2 + dn;
        out[i] = b1*m1 + b2*m2 + b0*w;
        m2 = m1; m1 = w;
    }
    dn = -dn;
}

Я понимаю, что «регистр» несколько не нужен, учитывая, как умные современные компиляторы относятся к такого рода вещам.Мой вопрос заключается в том, есть ли потенциальные преимущества в производительности для хранения коэффициентов фильтра в отдельных переменных вместо использования массивов и разыменования значений?Будет ли ответ на этот вопрос зависеть от целевой платформы?

т.е.

out[i] = b[1]*m[1] + b[2]*m[2] + b[0]*w;

против

out[i] = b1*m1 + b2*m2 + b0*w;

Ответы [ 3 ]

5 голосов
/ 22 марта 2012

Это действительно зависит от вашего компилятора и параметров оптимизации.Вот мое мнение:

  • Любой современный компилятор просто проигнорирует register.Это просто подсказка компилятору, а современные просто не используют его.
  • Доступ к постоянным индексам в цикле обычно оптимизируется при компиляции с включенной оптимизацией.В некотором смысле, использование переменных или массива, как вы показали, не имеет значения.
  • Всегда, всегда выполняйте тесты и смотрите на сгенерированный код для критических частей кода.

РЕДАКТИРОВАТЬ: ОК, просто из любопытства я написал небольшую программу и получил "идентичный" код, сгенерированный при полной оптимизации с VS2010.Вот что я получаю внутри цикла для рассматриваемого выражения (в обоих случаях оно абсолютно идентично):

0128138D  fmul        dword ptr [eax+0Ch]  
01281390  faddp       st(1),st  
01281392  fld         dword ptr [eax+10h]  
01281395  fld         dword ptr [w]  
01281398  fld         st(0)  
0128139A  fmulp       st(2),st  
0128139C  fxch        st(2)  
0128139E  faddp       st(1),st  
012813A0  fstp        dword ptr [ecx+8]  

Обратите внимание, что я добавил несколько строк для вывода результатов, чтобы убедиться, что компилятор не простооптимизировать все.Вот код:

#include <iostream>
#include <iterator>
#include <algorithm>

class test1 
{
    float a1, a2, b0, b1, b2;
    float dn;
    float m1, m2;

public:
    void processBiquad(const float* in, float* out, unsigned length)
    {
        for(unsigned i = 0; i < length; ++i)
        {
            float w = in[i] - a1*m1 - a2*m2 + dn;
            out[i] = b1*m1 + b2*m2 + b0*w;
            m2 = m1; m1 = w;
        }
        dn = -dn;
    }
};

class test2 
{
    float a[2], b[3];
    float dn;
    float m1, m2;

public:
    void processBiquad(const float* in, float* out, unsigned length)
    {
        for(unsigned i = 0; i < length; ++i)
        {
            float w = in[i] - a[0]*m1 - a[1]*m2 + dn;
            out[i] = b[0]*m1 + b[1]*m2 + b[2]*w;
            m2 = m1; m1 = w;
        }
        dn = -dn;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    test1 t1;
    test2 t2;

    float a[1000];
    float b[1000];

    t1.processBiquad(a, b, 1000);
    t2.processBiquad(a, b, 1000);

    std::copy(b, b+1000, std::ostream_iterator<float>(std::cout, " "));

    return 0;
}
3 голосов
/ 22 марта 2012

Я не уверен, но это:

out[i] = b[1]*m[1] + b[2]*m[2] + b[0]*w;

может быть хуже, потому что он компилируется с косвенным доступом, и это хуже, чем производительность прямого доступа.

Единственный способ увидеть это - проверить скомпилированный ассемблер и профилировать код.

2 голосов
/ 22 марта 2012

Вы, вероятно, получите выгоду, если сможете объявить коэффициенты b0, b1, b2 как постоянные.Код будет более эффективным, если любой из ваших операндов будет известен и исправлен во время компиляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...