【发布时间】:2019-03-30 21:37:55
【问题描述】:
假设我必须将两个数组相乘,例如 A[MAX_BUFFER] 和 B[MAX_BUFFER](带有 MAX_BUFFER = 256)。
由于某种原因,每个B[MAX_BUFFER] 值都以固定控制率(例如8)计算,因为每个值都会被大量处理。
稍后,考虑到(引入的)不同间距,我需要将彼此相乘到C[MAX_BUFFER]。因此,A 有 256 个值,我将得到一个大小可变的 B(本例中为 32,因为控制率为 8)。
这是example code:
#include <iostream>
#include <math.h>
#define MAX_BUFFER 256
double HeavyFunction(double value) {
if (value == 0) return 0.0;
return pow(10.0, value); // heavy operations on value...
}
int main()
{
int blockSize = 256;
int controlRate = 8;
double A[MAX_BUFFER];
double B[MAX_BUFFER];
double C[MAX_BUFFER];
// fill A
for (int sampleIndex = 0; sampleIndex < blockSize; sampleIndex++) {
A[sampleIndex] = sampleIndex;
}
// fill B (control rated)
int index = 0;
for (int sampleIndex = 0; sampleIndex < blockSize; sampleIndex += controlRate, index++) {
B[index] = HeavyFunction(index);
}
// calculate C
for (int sampleIndex = 0; sampleIndex < blockSize; sampleIndex++) {
C[sampleIndex] = A[sampleIndex] + B[sampleIndex / 8];
std::cout << C[sampleIndex] << std::endl;
}
}
我需要性能,因为我将并行处理许多这些操作,在 1 秒内发送许多数据(例如 44100 个样本拆分为 blockSize MAX_BUFFER)。
我想避免分支(即if)和除法(如上例所示),它们不是类似 CPU 的操作(处理大量数据)。
在之前的例子中,这里会引入sampleIndex / 8 * N“徒劳”的N操作;如果我为数百万个样本调用该程序...
您将如何以一种花哨且轻松的方式为 CPU 重构此代码?
【问题讨论】:
-
任何体面的优化编译器都会用右移替换
/8。查看在担心数组索引“开销”之前生成的程序集,很可能根本没有。 -
听起来您不需要这种级别的优化(除非您有严格的硬件限制,否则在 1 秒内天真地执行 44100 次乘法是微不足道的),但您可能会从使用 SSE/AVX 中受益更多执行操作的说明,而不是您担心分支。
-
@markzzz 看generated assembly code,没有8除,除以移位,看
sar eax, 3指令。 -
为什么 HeavyFunction(0) = 0 ?
-
这只是一个例子,不用担心:)
标签: c++ optimization branch-prediction