OpenMP 矩阵乘法问题
OpenMP Matrix Multiplication Issues
我正在尝试乘以矩阵的值。
#include <stdio.h>
#include <omp.h>
#include <time.h>
#include <stdlib.h>
#include <omp.h>
#define N 2048
#define FactorIntToDouble 1.1;
#define THREAD_NUM 4
double firstMatrix [N] [N] = {0.0};
double secondMatrix [N] [N] = {0.0};
double matrixMultiResult [N] [N] = {0.0};
// Sync
void matrixMulti() {
for(int row = 0 ; row < N ; row++){
for(int col = 0; col < N ; col++){
double resultValue = 0;
for(int transNumber = 0 ; transNumber < N ; transNumber++) {
resultValue += firstMatrix [row] [transNumber] * secondMatrix [transNumber] [col] ;
}
matrixMultiResult [row] [col] = resultValue;
}
}
}
void matrixInit() {
for(int row = 0 ; row < N ; row++ ) {
for(int col = 0 ; col < N ;col++){
srand(row+col);
firstMatrix [row] [col] = ( rand() % 10 ) * FactorIntToDouble;
secondMatrix [row] [col] = ( rand() % 10 ) * FactorIntToDouble;
}
}
}
// Parallel
void matrixMulti2(int start, int end) {
printf("Op: %d - %d\n", start, end);
for(int row = start ; row < end ; row++){
for(int col = 0; col < N ; col++){
double resultValue = 0;
for(int transNumber = 0 ; transNumber < N ; transNumber++) {
resultValue += firstMatrix [row] [transNumber] * secondMatrix [transNumber] [col] ;
}
matrixMultiResult [row] [col] = resultValue;
}
}
}
void process1(){
clock_t t1 = clock();
#pragma omp parallel
{
int thread = omp_get_thread_num();
int thread_multi = N / 4;
int start = (thread) * thread_multi;
int end = 0;
if(thread == (THREAD_NUM - 1)){
end = (start + thread_multi);
}else{
end = (start + thread_multi) - 1;
}
matrixMulti2(start, end);
}
clock_t t2 = clock();
printf("time 2: %ld\n", t2-t1);
}
int main(){
matrixInit();
clock_t t1 = clock();
matrixMulti();
clock_t t2 = clock();
printf("time: %ld", t2-t1);
process1();
return 0;
}
我有并行版和同步版。但是并行版本比同步版本长。
当前同步大约需要 90 秒,并行超过 100 秒。这对我来说毫无意义。
我的逻辑是将矩阵从前 4 个语句分成 4 个部分。我认为这是合乎逻辑的。
在我完成这部分之后。我想弄清楚如何进一步加快并行的这个过程。可能使用 Strassen 的矩阵乘法。我只是不知道从哪里开始或如何到达这一点。
我已经花了大约 5 个小时来解决这个问题。
这里是:
// Sync
void matrixMulti() {
#pragma omp parallel for collapse(2)
for(int row = 0 ; row < N ; row++){
for(int col = 0; col < N ; col++){
double resultValue = 0;
for(int transNumber = 0 ; transNumber < N ; transNumber++) {
resultValue += firstMatrix [row] [transNumber] * secondMatrix [transNumber] [col] ;
}
matrixMultiResult [row] [col] = resultValue;
}
}
}
更新:这是我使用 gcc 10.3 -O3 -fopenmp 标志在 8 核系统上得到的(我向您展示程序的输出和 linux 时间命令的结果):
main()
已更改为使用 omp_get_wtime()
测量时间,因为在 linux 中 clock()
测量处理器时间:
double t1 = omp_get_wtime();
matrixMulti();
double t2 = omp_get_wtime();
printf("time: %f", t2-t1);
串口程序:
time: 25.895234
real 0m33.296s
user 0m33.139s
sys 0m0.152s
使用:#pragma omp parallel for
time: 3.573521
real 0m11.120s
user 0m32.205s
sys 0m0.136s
使用:#pragma omp parallel for collapse(2)
time: 5.466674
real 0m12.786s
user 0m49.978s
sys 0m0.248s
结果表明矩阵的初始化需要大约。 8 s,所以它也可能值得并行化。没有 collapse(2)
程序运行得更快,所以不要使用 collapse(2)
子句。
请注意,在您的系统上,您可能会获得不同的速度提升甚至降低,具体取决于您的硬件。矩阵乘法的速度很大程度上取决于内存的速度 read/write。共享内存多核系统(即大多数 PC、笔记本电脑)在该程序并行化后可能不会显示任何速度提升,但分布式内存多核系统(即高端服务)肯定会显示性能提升。有关详细信息,请阅读例如this.
更新 2:在 Ryzen 7 5800X 上我得到了 41.6 s
vs 1.68 s
,这比内核数量的增加更大。这是因为当所有内核都被使用时,有更多的缓存内存可用。
我正在尝试乘以矩阵的值。
#include <stdio.h>
#include <omp.h>
#include <time.h>
#include <stdlib.h>
#include <omp.h>
#define N 2048
#define FactorIntToDouble 1.1;
#define THREAD_NUM 4
double firstMatrix [N] [N] = {0.0};
double secondMatrix [N] [N] = {0.0};
double matrixMultiResult [N] [N] = {0.0};
// Sync
void matrixMulti() {
for(int row = 0 ; row < N ; row++){
for(int col = 0; col < N ; col++){
double resultValue = 0;
for(int transNumber = 0 ; transNumber < N ; transNumber++) {
resultValue += firstMatrix [row] [transNumber] * secondMatrix [transNumber] [col] ;
}
matrixMultiResult [row] [col] = resultValue;
}
}
}
void matrixInit() {
for(int row = 0 ; row < N ; row++ ) {
for(int col = 0 ; col < N ;col++){
srand(row+col);
firstMatrix [row] [col] = ( rand() % 10 ) * FactorIntToDouble;
secondMatrix [row] [col] = ( rand() % 10 ) * FactorIntToDouble;
}
}
}
// Parallel
void matrixMulti2(int start, int end) {
printf("Op: %d - %d\n", start, end);
for(int row = start ; row < end ; row++){
for(int col = 0; col < N ; col++){
double resultValue = 0;
for(int transNumber = 0 ; transNumber < N ; transNumber++) {
resultValue += firstMatrix [row] [transNumber] * secondMatrix [transNumber] [col] ;
}
matrixMultiResult [row] [col] = resultValue;
}
}
}
void process1(){
clock_t t1 = clock();
#pragma omp parallel
{
int thread = omp_get_thread_num();
int thread_multi = N / 4;
int start = (thread) * thread_multi;
int end = 0;
if(thread == (THREAD_NUM - 1)){
end = (start + thread_multi);
}else{
end = (start + thread_multi) - 1;
}
matrixMulti2(start, end);
}
clock_t t2 = clock();
printf("time 2: %ld\n", t2-t1);
}
int main(){
matrixInit();
clock_t t1 = clock();
matrixMulti();
clock_t t2 = clock();
printf("time: %ld", t2-t1);
process1();
return 0;
}
我有并行版和同步版。但是并行版本比同步版本长。
当前同步大约需要 90 秒,并行超过 100 秒。这对我来说毫无意义。
我的逻辑是将矩阵从前 4 个语句分成 4 个部分。我认为这是合乎逻辑的。
在我完成这部分之后。我想弄清楚如何进一步加快并行的这个过程。可能使用 Strassen 的矩阵乘法。我只是不知道从哪里开始或如何到达这一点。
我已经花了大约 5 个小时来解决这个问题。
这里是:
// Sync
void matrixMulti() {
#pragma omp parallel for collapse(2)
for(int row = 0 ; row < N ; row++){
for(int col = 0; col < N ; col++){
double resultValue = 0;
for(int transNumber = 0 ; transNumber < N ; transNumber++) {
resultValue += firstMatrix [row] [transNumber] * secondMatrix [transNumber] [col] ;
}
matrixMultiResult [row] [col] = resultValue;
}
}
}
更新:这是我使用 gcc 10.3 -O3 -fopenmp 标志在 8 核系统上得到的(我向您展示程序的输出和 linux 时间命令的结果):
main()
已更改为使用 omp_get_wtime()
测量时间,因为在 linux 中 clock()
测量处理器时间:
double t1 = omp_get_wtime();
matrixMulti();
double t2 = omp_get_wtime();
printf("time: %f", t2-t1);
串口程序:
time: 25.895234
real 0m33.296s
user 0m33.139s
sys 0m0.152s
使用:#pragma omp parallel for
time: 3.573521
real 0m11.120s
user 0m32.205s
sys 0m0.136s
使用:#pragma omp parallel for collapse(2)
time: 5.466674
real 0m12.786s
user 0m49.978s
sys 0m0.248s
结果表明矩阵的初始化需要大约。 8 s,所以它也可能值得并行化。没有 collapse(2)
程序运行得更快,所以不要使用 collapse(2)
子句。
请注意,在您的系统上,您可能会获得不同的速度提升甚至降低,具体取决于您的硬件。矩阵乘法的速度很大程度上取决于内存的速度 read/write。共享内存多核系统(即大多数 PC、笔记本电脑)在该程序并行化后可能不会显示任何速度提升,但分布式内存多核系统(即高端服务)肯定会显示性能提升。有关详细信息,请阅读例如this.
更新 2:在 Ryzen 7 5800X 上我得到了 41.6 s
vs 1.68 s
,这比内核数量的增加更大。这是因为当所有内核都被使用时,有更多的缓存内存可用。