OpenMP 并行乘法比顺序乘法慢
OpenMP parallel multiplication slower than Sequential multiplication
我正在学习 OpenMP,我正在尝试完成一个简单的任务:A[r][c] * X[c] = B [r](矩阵向量乘法)。
问题是:顺序代码比并行代码快,我不知道为什么!
我的代码:
#include <omp.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/types.h>
// Defined variables
#define row_matriz_A 80000
#define col_matriz_A 800
#define THREADS_NUM 4
// FUNCAO - GERAR MATRIZES
void gerarMatrizes(int r, int c, int mA[], int vX[], int vB[]){...}
// FUNCAO - SEQUENTIAL MULTIPLICATION
void multSequencial(int r, int c, int mA[], int vX[], int vB[]){
// Variables
int i, j, offset, sum;
struct timeval tv1,tv2;
double t1, t2;
// Begin Time
gettimeofday(&tv1, NULL);
t1 = (double)(tv1.tv_sec) + (double)(tv1.tv_usec)/ 1000000.00;
for(i = 0; i < r; i++){
sum = 0;
for(j = 0; j < c; j++){
offset = i * c + j;
sum += mA[offset] * vX[j];
}
vB[i] = sum;
}
// End time
gettimeofday(&tv2, NULL);
t2 = (double)(tv2.tv_sec) + (double)(tv2.tv_usec)/ 1000000.00;
printf("\nO tempo de execucao sequencial foi: %lf segundos.\n", (t2 - t1));
return;
}
// FUNCAO - MULTIPLICACAO PARALELA COM OpenMP
void matvecHost(int r, int c, int mA[], int vX[], int vB[]){
// Variaveis
int tID, i, j, offset, sum;
struct timeval tv1, tv2;
double t1, t2;
// Init vB
for(i = 0; i < r; i++) vB[i] = 0;
// BEGIN Time
gettimeofday(&tv1, NULL);
t1 = (double)(tv1.tv_sec) + (double)(tv1.tv_usec)/ 1000000.00;
omp_set_num_threads(THREADS_NUM);
#pragma omp parallel private(tID, i, j) shared(mA, vB, vX)
{
tID = omp_get_thread_num();
#pragma omp for
for(i = 0; i < r; i++){
sum = 0;
for(j = 0; j < c; j++){
offset = i * c + j;
sum += mA[offset] * vX[j];
}
vB[i] = sum;
}
}
// End time
gettimeofday(&tv2, NULL);
t2 = (double)(tv2.tv_sec) + (double)(tv2.tv_usec)/ 1000000.00;
printf("\nO tempo de execucao OpenMP foi: %lf segundos.\n", (t2 - t1));
return;
}
// FUNCAO - PRINCIPAL
int main(int argc, char * argv[]) {
int row, col;
row = row_matriz_A;
col = col_matriz_A;
int *matrizA = (int *)calloc(row * col, sizeof(int));
int *vectorX = (int *)calloc(col * 1, sizeof(int));
int *vectorB = (int *)calloc(row * 1, sizeof(int));
gerarMatrizes(row, col, matrizA, vectorX, vectorB);
multSequencial(row, col, matrizA, vectorX, vectorB);
matvecHost(row, col, matrizA, vectorX, vectorB);
return 0;
}
以前没有的解决方案:
- 在我的平方中使用折叠
- 增加行和列大小
- 增加线程数(老师推荐使用线程数==线程物理数)
- 使用 malloc 代替 m[i][j]
编辑 - 答案
我的并行块已根据正确答案正确更改:
#pragma omp parallel private(i, j, sum) shared(mA, vB, vX)
{
#pragma omp for
for(i = 0; i < r; i++){
sum = 0;
for(j = 0; j < c; j++){
sum += mA[i * c + j] * vX[j];
}
vB[i] = sum;
}
}
我还有点疑惑:
- 如果我在 我的并行块中定义
i
、j
和 sum
,它们会自动设置为私有吗?这是否提高了我的代码速度?
您在 sum
和 offset
上存在竞争条件 - 它们在线程之间共享,而不是线程私有的。
这也可能解释了减速:在 x86 上,CPU 实际上会努力确保访问共享变量 "work"。这涉及在每次(!)写入 offset
和 sum
后刷新缓存行 - 因此所有线程都疯狂地写入相同的变量,但每个线程都必须等到前一个线程写入(在不同的核心上)在刷新后再次到达本地缓存。当然,它会产生完全荒谬的结果。
我不知道您为什么要在函数的开头声明所有变量 - 这很容易出现此类错误。如果您在尽可能小的范围内声明 i
、j
、sum
和 offset
(以及未使用的 tID
),您将永远不会有这个问题,因为在那种情况下它们会自动成为线程私有的。
我正在学习 OpenMP,我正在尝试完成一个简单的任务:A[r][c] * X[c] = B [r](矩阵向量乘法)。 问题是:顺序代码比并行代码快,我不知道为什么! 我的代码:
#include <omp.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/types.h>
// Defined variables
#define row_matriz_A 80000
#define col_matriz_A 800
#define THREADS_NUM 4
// FUNCAO - GERAR MATRIZES
void gerarMatrizes(int r, int c, int mA[], int vX[], int vB[]){...}
// FUNCAO - SEQUENTIAL MULTIPLICATION
void multSequencial(int r, int c, int mA[], int vX[], int vB[]){
// Variables
int i, j, offset, sum;
struct timeval tv1,tv2;
double t1, t2;
// Begin Time
gettimeofday(&tv1, NULL);
t1 = (double)(tv1.tv_sec) + (double)(tv1.tv_usec)/ 1000000.00;
for(i = 0; i < r; i++){
sum = 0;
for(j = 0; j < c; j++){
offset = i * c + j;
sum += mA[offset] * vX[j];
}
vB[i] = sum;
}
// End time
gettimeofday(&tv2, NULL);
t2 = (double)(tv2.tv_sec) + (double)(tv2.tv_usec)/ 1000000.00;
printf("\nO tempo de execucao sequencial foi: %lf segundos.\n", (t2 - t1));
return;
}
// FUNCAO - MULTIPLICACAO PARALELA COM OpenMP
void matvecHost(int r, int c, int mA[], int vX[], int vB[]){
// Variaveis
int tID, i, j, offset, sum;
struct timeval tv1, tv2;
double t1, t2;
// Init vB
for(i = 0; i < r; i++) vB[i] = 0;
// BEGIN Time
gettimeofday(&tv1, NULL);
t1 = (double)(tv1.tv_sec) + (double)(tv1.tv_usec)/ 1000000.00;
omp_set_num_threads(THREADS_NUM);
#pragma omp parallel private(tID, i, j) shared(mA, vB, vX)
{
tID = omp_get_thread_num();
#pragma omp for
for(i = 0; i < r; i++){
sum = 0;
for(j = 0; j < c; j++){
offset = i * c + j;
sum += mA[offset] * vX[j];
}
vB[i] = sum;
}
}
// End time
gettimeofday(&tv2, NULL);
t2 = (double)(tv2.tv_sec) + (double)(tv2.tv_usec)/ 1000000.00;
printf("\nO tempo de execucao OpenMP foi: %lf segundos.\n", (t2 - t1));
return;
}
// FUNCAO - PRINCIPAL
int main(int argc, char * argv[]) {
int row, col;
row = row_matriz_A;
col = col_matriz_A;
int *matrizA = (int *)calloc(row * col, sizeof(int));
int *vectorX = (int *)calloc(col * 1, sizeof(int));
int *vectorB = (int *)calloc(row * 1, sizeof(int));
gerarMatrizes(row, col, matrizA, vectorX, vectorB);
multSequencial(row, col, matrizA, vectorX, vectorB);
matvecHost(row, col, matrizA, vectorX, vectorB);
return 0;
}
以前没有的解决方案:
- 在我的平方中使用折叠
- 增加行和列大小
- 增加线程数(老师推荐使用线程数==线程物理数)
- 使用 malloc 代替 m[i][j]
编辑 - 答案
我的并行块已根据正确答案正确更改:
#pragma omp parallel private(i, j, sum) shared(mA, vB, vX)
{
#pragma omp for
for(i = 0; i < r; i++){
sum = 0;
for(j = 0; j < c; j++){
sum += mA[i * c + j] * vX[j];
}
vB[i] = sum;
}
}
我还有点疑惑:
- 如果我在 我的并行块中定义
i
、j
和sum
,它们会自动设置为私有吗?这是否提高了我的代码速度?
您在 sum
和 offset
上存在竞争条件 - 它们在线程之间共享,而不是线程私有的。
这也可能解释了减速:在 x86 上,CPU 实际上会努力确保访问共享变量 "work"。这涉及在每次(!)写入 offset
和 sum
后刷新缓存行 - 因此所有线程都疯狂地写入相同的变量,但每个线程都必须等到前一个线程写入(在不同的核心上)在刷新后再次到达本地缓存。当然,它会产生完全荒谬的结果。
我不知道您为什么要在函数的开头声明所有变量 - 这很容易出现此类错误。如果您在尽可能小的范围内声明 i
、j
、sum
和 offset
(以及未使用的 tID
),您将永远不会有这个问题,因为在那种情况下它们会自动成为线程私有的。