给定浮点矩阵A [N,M]和浮点数组T [M],我想使用OpenMP并行化以下代码:
for ( int i = 0; i < N; i++ )
{
T[0] = A[i][0];
for ( int j = 1; j < M; j++ )
T[j] = f(A[i][j]-T[j-1]) + A[i][j];
float v = T[M-1];
for ( int j = M-2; j >=0; j-- )
{
v = g(A[i][j]-v);
A[i][j] = T[j] + v;
}
}
其中f和g是非线性函数。这是一个递归过滤器。我的第一次尝试(我是OpenMP的新手)是并行化外部循环并将T分配为维度#threads X M的矩阵,其中#threads = omp_get_max_threads():
#pragma omp parallel for
for ( int i = 0; i < N; i++ )
{
Let T1 point to the row of T indexed by the current thread (given by omp_get_thread_num())
T1[0] = A[i][0];
for ( int j = 1; j < M; j++ )
T1[j] = f(A[i][j]-T1[j-1]) + A[i][j];
float v = T1[M-1];
for ( int j = M-2; j >=0; j-- )
{
v = g(A[i][j]-v);
A[i][j] = T1[j] + v;
}
}
这样,每个线程都使用自己的T内存。我在我的8核i7 CPU上进行了测试,加速大约是5倍,但在我的4核智能手机CPU上,我得到了一个非常小的加速(如1.3x - 1.5x)。我的问题是:
更新1。
为了测试它,我使用了在8核i7机器上启用OpenMP的MS Visual Studio,而在我的智能手机上,我使用了Android NDK提供的工具链,使用-fopen -O3 -funroll-loops
标志。我在Win上使用QueryPerformanceCounter
,在Android上使用以下代码:
///
double CUtil::GetTimeMs()
{
struct timespec res;
clock_gettime(CLOCK_REALTIME, &res);
return 1000.0 * res.tv_sec + (double) res.tv_nsec / 1e6;
}
更新2。 我已经更新了Android上的加速数据。
答案 0 :(得分:1)
我的感觉是你有正确的并行化方法。
但是,由于您的T
数组似乎仅用作临时存储,而不是将其分配为2D数组,第一维是要使用的线程数,我只需将其分配到{{ 1}}区域为私有。这不应该产生太大的影响,但可以简化在NUMA环境中确保数据位置的工作,并避免任何潜在的错误共享。
代码如下所示:
parallel
现在,它是否会对您的代码在性能方面产生任何影响,我对此持怀疑态度。但是,我提请您注意使用#pragma omp parallel
{
float *T = new float[M];
#pragma omp for schedule( static )
for ( int i = 0; i < N; i++ ) {
float *AA = A[i]; // this "optimisation" is arguable and can be ignored
T[0] = AA[0];
for ( int j = 1; j < M; j++ ) {
T[j] = f( AA[j] - T[j-1] ) + AA[j];
}
float v = T1[M-1];
for ( int j = M-2; j >= 0; j-- ) {
v = g( AA[j] - v );
AA[j] = T[j] + v;
}
}
delete[] T;
}
作为OpenMP代码的计时器(以及全球范围内的多线程代码)。关键是(在POSIX系统上至少IINM)clock()
返回当前线程及其子项的 CPU时间。同样,IINM,在Windows上,相同的函数只返回调用线程的CPU时间
因此,如果有机会,你的电脑在Windows上,而你的手机在Android上,在以前的平台上,你只为一个线程打印CPU,而后者则打印所有线程的累计CPU时间......
这是一个非常投机的想法,但无论如何我都不能鼓励你放弃clock()
并使用clock()
来恢复已经过去的挂钟时间,这就是你真正想要的得到。
修改强>:
好好阅读你的更新(在我开始写这个答案和它的出版物之间出现),看起来我有点正确(对于Windows和Android)。但是,对于omp_get_wtime()
来说,我错了。但是,在两个平台上使用像clock()
这样的通用计时器都是个好主意。
尽管如此,我不相信我到目前为止提出的任何建议都可以解释两台机器上的加速之间的差异。我怀疑底线可能只是硬件特征。同样,这是非常推测的(特别是考虑到我从未试图在智能手机上运行任何东西),但这可能只是两台机器上内存带宽,高速缓存大小和CPU性能之间(非常)不同平衡的结果:
评估这种情况是否确实如此的好方法是使用两个平台的roofline model并计算算法的算术强度,以便在图上绘制它。这将为您提供一个关于您的表现以及是否有进一步改进空间的公平想法。