通过向量OpenMP C进行矩阵乘法

时间:2014-05-02 10:15:37

标签: c openmp

我试图在C(OpenMP)中通过向量乘法来编写矩阵 但是当我添加处理器时,我的程序会变慢...

1 proc - 1,3 s
2 proc - 2,6 s
4 proc - 5,47 s

我在我的PC(核心i5)和我们学校的群集上进行了测试,结果相同(程序变慢)

这是我的代码(矩阵是10000 x 10000),矢量是10000:

double start_time = clock();
#pragma omp parallel private(i) num_threads(4)
{
    tid = omp_get_thread_num();
    world_size = omp_get_num_threads();
    printf("Threads: %d\n",world_size);

    for(y = 0; y < matrix_size ; y++){
        #pragma omp parallel for private(i) shared(results, vector, matrix)
        for(i = 0; i < matrix_size; i++){
                results[y] = results[y] + vector[i]*matrix[i][y];   
        }
    }
}
double end_time = clock();
double result_time = (end_time - start_time) / CLOCKS_PER_SEC;
printf("Time: %f\n", result_time);

我的问题是:有什么错误吗?对我来说,它似乎很简单,应该加快

3 个答案:

答案 0 :(得分:4)

我基本上已经回答了这个问题parallelizing-matrix-times-a-vector-by-columns-and-by-rows-with-openmp

当您写信至results[y]时,您有竞争条件。要解决此问题,并且仍然并行化内部循环,您必须创建results[y]的私有版本,并行填充它们,然后将它们合并到一个关键部分。

在下面的代码中,我假设您正在使用double,将其替换为floatint或您正在使用的任何数据类型(请注意您的内部循环遍历matrix[i][y]的第一个索引,它是缓存不友好的。)

#pragma omp parallel num_threads(4)
{
    int y,i;
    double* results_private = (double*)calloc(matrix_size, sizeof(double));
    for(y = 0; y < matrix_size ; y++) {
        #pragma omp for
        for(i = 0; i < matrix_size; i++) {
            results_private[y] += vector[i]*matrix[i][y];   
        }
    }
    #pragma omp critical
    {
        for(y=0; y<matrix_size; y++) results[y] += results_private[y];
    }
    free(results_private);
}

如果这是家庭作业,你想真正给你的教练留下深刻的印象,那么在没有关键部分的情况下进行合并是可能的。请参阅此链接以了解该做什么fill-histograms-array-reduction-in-parallel-with-openmp-without-using-a-critic,但我无法保证会更快。

答案 1 :(得分:0)

我暂时没有进行任何并行编程,也没有任何数学,但是你不想并行分割矩阵的行而不是列吗?

如果您尝试这样做会发生什么:

double start_time = clock();
#pragma omp parallel private(i) num_threads(4)
{
tid = omp_get_thread_num();
world_size = omp_get_num_threads();
printf("Threads: %d\n",world_size);

#pragma omp parallel for private(y) shared(results, vector, matrix)
for(y = 0; y < matrix_size ; y++){

    for(i = 0; i < matrix_size; i++){
            results[y] = results[y] + vector[i]*matrix[i][y];   
    }
}
}
double end_time = clock();
double result_time = (end_time - start_time) / CLOCKS_PER_SEC;
printf("Time: %f\n", result_time);

另外,你确定一切都可以编译并链接到openMP吗?

答案 2 :(得分:0)

您遇到缓存冲突的典型案例。

考虑到CPU上的缓存行可能长达64个字节。让一个处理器/核心写入前4个字节(float)会导致该高速缓存行在每个其他L1 / L2和L3上无效。这是一个很大的开销。

更好地对数据进行分区!

 #pragma omp parallel for private(i) shared(results, vector, matrix) schedule(static,16)

应该做的伎俩。如果这没有帮助,请增加chunksize。

另一个优化是在将结果刷新到内存之前将结果存储在本地。

此外,这是一个OpenMP的东西,但你不需要为循环开始一个新的并行区域(每次提到parallel都会启动一个新团队):

#pragma omp parallel default(none) \
        shared(vector, matrix) \
        firstprivate(matrix_size) \
        num_threads(4)
{
    int i, y;
    #pragma omp for schedule(static,16)
    for(y = 0; y < matrix_size ; y++){
        double result = 0;
        for(i = 0; i < matrix_size; i++){
                results += vector[i]*matrix[i][y];   
        }
        result[y] = result;
    }
}