【发布时间】:2016-06-08 11:00:09
【问题描述】:
我有一个关于并行编程的学校任务,但我遇到了很多问题。 我的任务是创建给定矩阵乘法代码的并行版本并测试其性能(是的,它必须按 KIJ 顺序排列):
void multiply_matrices_KIJ()
{
for (int k = 0; k < SIZE; k++)
for (int i = 0; i < SIZE; i++)
for (int j = 0; j < SIZE; j++)
matrix_r[i][j] += matrix_a[i][k] * matrix_b[k][j];
}
这是我目前想出的:
void multiply_matrices_KIJ()
{
for (int k = 0; k < SIZE; k++)
#pragma omp parallel
{
#pragma omp for schedule(static, 16)
for (int i = 0; i < SIZE; i++)
for (int j = 0; j < SIZE; j++)
matrix_r[i][j] += matrix_a[i][k] * matrix_b[k][j];
}
}
这就是我发现一些令我困惑的地方。这个并行版本的代码运行速度比非并行版本慢约 50%。速度差异仅根据矩阵大小(测试的 SIZE = 128、256、512、1024、2048 以及各种时间表版本 - 动态、静态、完全不带它等等)而略有不同。
有人可以帮助我了解我做错了什么吗?可能是因为我使用的是 KIJ 命令,而使用 openMP 并不会变得更快?
编辑:
我在 Windows 7 PC 上工作,使用 Visual Studio 2015 社区版,在发布 x86 模式下编译(x64 也无济于事)。我的 CPU 是:Intel Core i5-2520M CPU @ 2,50GHZ(是的,是的,它是一台笔记本电脑,但我在家用 I7 PC 上得到了相同的结果)
我正在使用全局数组:
float matrix_a[SIZE][SIZE];
float matrix_b[SIZE][SIZE];
float matrix_r[SIZE][SIZE];
我正在为矩阵 a 和 b 分配随机(浮点)值,矩阵 r 用 0 填充。
到目前为止,我已经使用各种矩阵大小(128、256、512、1024、2048 等)测试了代码。对于其中一些,它不适合缓存。 我当前版本的代码如下所示:
void multiply_matrices_KIJ()
{
#pragma omp parallel
{
for (int k = 0; k < SIZE; k++) {
#pragma omp for schedule(dynamic, 16) nowait
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
matrix_r[i][j] += matrix_a[i][k] * matrix_b[k][j];
}
}
}
}
}
为了清楚起见,我知道使用不同的循环顺序可以获得更好的结果,但事实就是如此 - 我必须使用 KIJ 顺序。我的任务是并行执行 KIJ for 循环并检查性能提升。我的问题是,我期望(ed)至少快一点执行(比我现在得到的最多快 5-10%)即使它是并行的 I 循环(不能用K 循环,因为我会得到不正确的结果,因为它是 matrix_r[i][j])。
这些是我使用上面显示的代码时得到的结果(我进行了数百次计算并获得了平均时间):
大小 = 128
- 系列版本:0,000608s
- 并行 I,调度(动态,16):0,000683s
- 并行 I,调度(静态,16):0,000647s
- 并行 J,无计划:0,001978s(这是我执行的地方 执行速度较慢)
大小 = 256
- 系列版本:0,005787s
- 并行 I,调度(动态,16):0,005125s
- 并行 I,调度(静态,16):0,004938s
- 平行 J,无时间表:0,013916s
大小 = 1024
- 系列版本:0,930250s
- 并行 I,调度(动态,16):0,865750s
- 并行 I,调度(静态,16):0,823750s
- 平行 J,无时间表:1,137000s
【问题讨论】:
-
您在 for k 循环中声明并行部分。这意味着,在该循环的每次迭代结束时,线程必须等到所有线程都完成迭代,然后开始下一次迭代。我会同时执行外循环,而不是内循环
-
你的编译选项是什么?你是用
-O3编译的吗?您使用的是什么编译器和操作系统。为什么要设置块大小? -
你是如何分配数组的?我猜您正在使用全局/静态数组,因为大小太大而无法放入缓存中,并且您可以将
matrix_r[i][j]与大型数组一起使用的唯一方法是使用全局/静态数组。 -
我在 Windows 7 上使用 Visual Studio 2015 社区版。我使用的是全局数组,它们的大小不适合缓存。
-
我的观察是,这个 kij-OpenMP 代码比 Visual Studio 2015、Windows 8(发布模式!)上的串行 kij 版本快很多。