OpenMP金字塔嵌套循环计数器

时间:2013-11-06 17:02:30

标签: c openmp

我想使用OpenMP来并行化我的代码,但我不确定我的循环如何保持其属性。

我知道内循环生成结果的次数,以及它有多大:

(取决于宽度的均匀性,内环表现不同,因此天花板和地板分区)

const size_t
    bytes_per_result = <something>,
    totalloops = width/2 * iceildiv(width, 2);

所以我可以将每个结果写入文件中的已知位置。为此,我只需分配一个大小的文件,然后将其倒回到开头:

FILE* f = fopen(<somefile>, "w");
fseek(f, totalloops * bytes_per_result - 1, SEEK_SET); //seek to before file end
fputc('\0', f); //write byte to allocate whole file
rewind(f);

然后我循环,并计算内部循环通过k运行的数字。在最后一个循环之后,k == totalloops

result_t result;
size_t i, j, k;
for (i=0, k=0; i<width; i++) {
    for (j=0; j<imin(i, width-i-1); j++, k++) {
        result = do_calculation(i, j);
        fseek(f, k * bytes_per_result, SEEK_SET);
        fwrite_result(f, result);
    }
}

现在我该如何并行化?并行化的东西当然是do_calculation部分,而寻求和写作必须一起声明#pragma omp critical。但是我如何使k表现得像我想要的那样?

OpenMP只能解析简单的for循环,最后只有一个增量表达式,而不是两个,所以我不能保留k++ ...

1 个答案:

答案 0 :(得分:0)

你可以分2步完成:

  1. 并行计算结果并将结果存储在RAM缓冲区中
  2. 将整个缓冲区写入文件。
  3. result_t buffer[MAXLEN];
    
    #pragma omp prarellel for
    for (size_t i=0; i<width; i++) {
        for (size_t j=0; j<imin(i, width-i+1); j++) {
            result_t result = do_calculation(i, j);
            size_t k=.....;
            buffer[k]=result;
        }
    }
    
    fwrite_buffer(f, buffer, total_length);
    

    更新

    由于结果日期很大(~10GB),您可能会花费大部分时间将数据写入磁盘。但是,多线程代码通常无法提高磁盘带宽限制任务的性能。你应该重新考虑多线程是否适合你的任务。

    如果缓冲区大小有问题,您可以保留原始设计,并使用omp critical来避免文件访问时的竞争条件。

    #pragma omp prarellel for schedule(dynamic,3)
    for (size_t i=0; i<width; i++) {
    result_t buffer[MAXLEN];
        for (size_t j=0; j<imin(i, width-i+1); j++) {
            result_t result = do_calculation(i, j);
            size_t k=ijw2k(i,j,width);
            #pragma omp critical {
                fseek(f, k * bytes_per_result, SEEK_SET);
                fwrite_buffer(f, result);
            }
        }
    }
    

    根据您的代码,计算k似乎有点复杂,但仍然可行。 k只是i, j, width的函数,我认为这不应该是你的问题。

    size_t ijw2k(size_t i, size_t j, size_t width) {
        size_t k;
        if (width % 2) {
            if (i<width-i+1) {
                ....
            } else {
                ....
            }
        } else {
            if (i<width-i+1) {
                ....
            } else {
                ....
            }
        }
        return k;
    }