c - 时间序列堆叠——C算法优化
问题描述
我正在解决一个问题,我想堆叠在不同位置记录的时间序列并提取相干信号。繁重的工作是在 C 中完成的,使用 Python 包装器来提供更友好的界面。我已经达到了对算法的理论正确性感到满意的地步,并希望尽可能地对其进行优化。我对 C 语言的理解足以编写一些可以与 openMP 并行运行的东西,但除此之外没有太多。
问题的优化很重要,因为我正在处理大型数据集 - 最多可堆叠 200 个时间序列,采样率高达 1000Hz,记录数月至数年。使用合理的计算设施,处理可以持续几天到几周。我正在对连续时间序列的块运行此堆叠步骤,以免占用内存。
我有几个问题:
有什么明显的我遗漏的东西会有所帮助(通过编译器进行优化,简化算法)?
到目前为止,最显着的收获是优化标志 -Ofast - 我已经阅读并只是想更多地了解为什么这会更快以及它对于我的目的是否“安全”?
我应该在哪里(除了通过 SO 拖网)了解更多关于这类问题的信息?我的研究中有其他问题,我想用 C 来解决!
算法
我将每个位置的时间序列连续堆叠在一个 3-D 网格体中。一旦完成给定单元的完整堆栈,我需要对结果取幂并按贡献时间序列的数量进行标准化。
#define MAX(a,b) (((a)>(b))?(a):(b))
EXPORT void migrate(double *sigPt, int32_t *indPt, double *mapPt, int32_t fsmp, int32_t lsmp, int32_t nsamp, int32_t nstation, int32_t avail, int64_t ncell, int64_t threads)
{
double *stnPt, *stkPt, *eStkPt;
int32_t *ttpPt;
int32_t ttp;
int32_t to, tm, st;
int64_t cell;
#pragma omp parallel for private(cell,stkPt,eStkPt,ttpPt,st,ttp,tm) num_threads(threads)
for (cell=0; cell<ncell; cell++)
{
stkPt = &mapPt[cell * (int64_t) nsamp];
eStkPt = &mapPt[cell * (int64_t) nsamp];
ttpPt = &indPt[cell * (int64_t) nstation];
for(st=0; st<nstation; st++)
{
ttp = MAX(0,ttpPt[st]);
stnPt = &sigPt[st*(fsmp + lsmp + nsamp) + ttp + fsmp];
for(tm=0; tm<nsamp; tm++)
{
stkPt[tm] += stnPt[tm];
}
}
for(tm=0; tm<nsamp; tm++)
{
eStkPt[tm] = exp(stkPt[tm] / avail);
}
}
}
我目前正在编译:
gcc -shared -fPIC -std=gnu99 ./source.c -fopenmp -Ofast -lm -o ./output
我读过了:
其中。如果我重复一个问题/我的问题定义不明确,我深表歉意。
解决方案
有什么明显的我遗漏的东西会有所帮助(通过编译器进行优化,简化算法)?
提议的代码似乎相当不错(GCC 应该能够对其进行矢量化并且并行化似乎还可以)。但这里有一些可能的建议来提高性能:
exp(stkPt[tm] / avail)
可以使用在循环外部定义并设置为 的常量pow(availFactor, stkPt[tm])
重写为可能更快的表达式。正如@tim18 所建议的那样,您还应该检查此循环是否已矢量化,因为指数通常计算速度很慢。availFactor
exp(1.0 / avail)
- 您可以尝试使用编译器标志
-march=native
以牺牲可移植性较差的二进制文件来使代码更快一点(如果您不想降低旧处理器的可移植性,您可以尝试-mtune=native
通常不如-march=native
. 关于你的处理器,这个选项可以让 GCC 使用 AVX 和 FMA 指令(在相对较新的处理器上可用),这应该可以加速你的代码。-mavx
您也可以使用和手动启用此类功能-mfma
。 - 您可以尝试调整您的算法,以便包含的热循环
stkPt[tm] += stnPt[tm]
主要用于缓存中的数据。这一点非常重要。事实上,算法中最热门的部分可能是内存受限的。一个好的起点是进行平铺(例如同时处理 2 个或 4 个nstation
)。 - 如果结果精度足够好,请考虑使用简单精度浮点类型而不是双精度。
不要忘记检查结果,因为这些优化可能会影响代码的准确性!
到目前为止,最重要的收获是优化标志 -Ofast - 我已经阅读并只是想更多地了解为什么这更快以及它是否对我的目的“安全”?
使用-Ofast
是不安全的。实际上,此选项启用-ffast-math
它可以启用更多选项,例如-funsafe-math-optimizations
或-ffinite-math-only
。因此,您的代码不应处理 NaN 值、无穷大和计算的准确性可能会低得多。关于您的期望,这可能是也可能不是问题。请注意,此选项有助于 GCC 加速指数计算(感谢矢量化)。
推荐阅读
- python - 我得到一个 TypeError: '<' 在 'str' 和 'int' 的实例之间不支持
- node.js - 具有标准和流量扩展的 Eslint 不起作用
- apache-spark - PySpark:加入后的计数()结果不一致
- excel - 管理员禁止加载解压的扩展。VBA EXCEL 出错
- javascript - undefined 不是对象(评估“this.store.dispatch”)
- delphi - 在对象检查器集合编辑器中检测所选项目
- google-analytics - 为什么按月的 %new session 与按该月每天的平均 %new session 不同
- django - 使用 docker-compose 中的命令导出后,bash 中没有环境变量
- django - 如何在 Django 管理表单中添加自定义操作按钮并发布信息
- html - 如何在我的网站上响应地调整 power bi 视觉效果