数字滤波器和std :: inner_product优化

时间:2012-04-04 11:16:06

标签: c++ filtering numeric

在数字过滤C ++应用程序中,我使用std::inner_product(带std::vector<double>std::deque<double>)来计算每个数据样本的滤波器系数和输入数据之间的点积。在对我的应用程序进行概要分析后,我发现在std::inner_product中花费了不少于85%的执行时间!

在GCC中,std::inner_product优化的范围是多少? 它是否使用SIMD指令?它是否执行循环展开?如何确保? 基于此,是否值得实现自定义点积函数(特别是如果系数的数量很少)? (但我希望尽可能保持函数的通用性)

更具体地说,这是我用来应用过滤器的代码:

std::deque<double> in(filterNum.size(), 0.0);
std::deque<double> out(filterDenom.size() - 1, 0.0);
const double gain = filterDenom.back();

for (unsigned int s = 0, size = data.size(); s < size; ++s) {
    in.pop_front();
    in.push_back(data[s] / gain);

    data[s] = inner_product(in.begin(), in.end(), filterNum.begin(),
        -inner_product(out.begin(), out.end(), filterDenom.begin(), 0.0));

    out.pop_front();
    out.push_back(data[s]);
}

通常,我使用二阶带通IIR滤波器,这意味着filterNumfilterDenom(滤波器的分子和分母系数)的大小为5. data是向量包含输入样本。

2 个答案:

答案 0 :(得分:1)

如果您直接编写代码,那么从中获取额外因子2应该不难。其中一部分可能来自于删除inner_product的一些通用性,但有些也可能来自消除deques的使用 - 如果你只是将一个指针放入你的输入数组,你可以将其索引并关闭过滤器数组。内部循环,并将指针递增到外部循环中的输入数组。

每个inner_products必须通过deques使用迭代器,

然后,大多数(编码)努力都会处理边缘条件。

从那里取出那个分区 - 它应该是在循环外计算的常数的乘法。

内部产品本身非常有效(没有太多可做的事情),但它需要在每次通过内部循环时增加两个迭代器。没有显式的循环展开,但是一个好的编译器可以展开一个简单的循环。并且编译器更有可能知道在遇到指令缓存问题之前展开循环的距离。

Deque迭代器在纯指针上的效率不如++。每个++至少有一个测试,可能有不止一个任务。

这是简单(FIR)滤波器的样子,不包括边缘条件的代码(在循环之外)

double norm = 1.0/sum;
double *p = data.values(); // start of input data
double *q = output.values();  // start of output buffer
int width = data.size() - filter.size();
for( int i = 0; i < width; ++i )
    {
    double *f = filter.values();
    double accumulator = ( f[0] * p[0] );
    for( int j = 1; j < filter.size(); ++j )
        {
        accumulator += ( f[i] * p[i] );
        }
    *q++ = accumulator * norm;
    }

请注意,遗漏了细节,这与您的过滤器不同,但它提供了这个想法。外环内部的内容很容易适应现代指令缓存。内循环可以由编译器展开。大多数现代架构可以并行添加和增加。

答案 1 :(得分:0)

您可以要求GCC在并行模式下计算<algorithms><numeric>中的大多数算法,如果您的数据集非常高,它可能会提升性能(我认为它实际上只使用它) OpenMP里面。)

然而,在小型数据集上,它可能会影响性能。

与其他解决方案的比较非常受欢迎!

http://gcc.gnu.org/onlinedocs/libstdc++/manual/parallel_mode.html